Hello,

Am Freitag, 21. November 2014 schrieb Steve Beattie:
> On Sat, Nov 15, 2014 at 11:46:41PM +0100, Christian Boltz wrote:
> > this patch changes aa.py and cleanprof.py to use the new capabiliy
> > rule class.
> > 
> > The most important details in the change are:
> > - the capability rules are stored in
> > 
> >   aa[profile][hat]['capability'] instead of
> >   aa[profile][hat]['allow']['capability'] and
> >   aa[profile][hat]['deny']['capability']
> >   (allow/deny is handled inside the capability_rules class)
> 
> Good.

:-)

> > - profile_known_capability() now just returns True or False. Before,
> > it> 
> >   returned different values for deny and allow, but the calling code
> >   doesn't care about this detail anyway.
> 
> For something that returns a boolean value, it feels like an awkwardly
> named function. is_known_capability?

Well, yes.

The final function will most probably be

    def is_known_rule(profile, rule_type, rule_obj):
        if profile[rule_type].is_covered(obj):
            [...]

and work for all rule types :-)

> > Some things are still a bit ugly (and commented as such). On the
> > long
> > term, I plan to change logparser so that it returns a set of *_rule
> > classes instead of the current array with parsed events. This will
> > remove some of the ugly tricks I had to add.
> > 
> > We should also come up with a function that initializes the
> > structure
> > for each profile in aa[profile][hat] - with that, we could drop
> > several safety checks I had to add to avoid problems with profiles
> > that don't contain a capability rule.
> 
> Ideally, we move to profiles/hats being encapsulated in a class of
> their own, for which the __init__() method can properly initialize
> the fields of the instance. 

Right, but that will be another patch (probably not this month, unless 
someone volunteers ;-)

> In the short term, can't we add a
> CapabilityRuleset when we start parsing a new profile/hat?

In theory, yes. We'll need to find all places where we initialize a new 
profile/hat - and finding places where it explodes was easier for 
obvious reasons ;-)

I searched for places that might need to be changed, see the attached 
init-profile-locations.diff. This patch comes without warranty ;-)  Also 
also note that I only checked aa.py. I wouldn't be surprised if
aa-cleanprof or aa-mergeprof also need to be changed.
(Any volunteer to test and implement that?)

> > I also had to add several
> > +                    if write_prof_data[name].get(segs, False):
> > +                       
> > write_prof_data[name][segs].delete_all_rules() in
> > serialize_profile_from_old_profile(). That's needed to avoid
> > writing rules twice.
> 
> Is this rule writing duplication because we no longer have an 'allow'
> and 'deny' layer in the hasher hierarchy for capabilities?

Exactly. See also this:

> > On the positive side, when we have converted everything to
> > rule classes, we can delete the four lines above each of these added
> > lines :-)

which deletes the rules from the "old" allow and deny branches.

> > === modified file 'utils/apparmor/aa.py'
> > --- utils/apparmor/aa.py    2014-11-15 11:51:24 +0000
> > +++ utils/apparmor/aa.py    2014-11-15 21:14:56 +0000

> > @@ -1628,16 +1630,16 @@
> > 
> >                                  if deleted:
> >                                      aaui.UI_Info(_('Deleted %s
> >                                      previous matching profile
> >                                      entries.') % deleted)> 
> > -                           
> > aa[profile][hat]['allow']['capability'][capability]['set'] = True -
> >                           
> > aa[profile][hat]['allow']['capability'][capability]['audit'] =
> > audit_toggle +                            else:
> > +                               
> > aa[profile][hat]['capability'].add_raw('%s capability %s,'% (audit,
> > capability))  # XXX yes, ugly ;-)
> I agree it's ugly, it suggests our interfaces into the classes are
> suboptimal. Why can't we have something like:
> 
>               cap_rule = CapabilityRule(capability, audit=audit)
>               aa[profile][hat]['capability'].add(cap_rule)
> 
> rather than playing games consing up strings. (Yes, you could write
> the two lines as a one-liner if you really wanted and skip the
> temporary cap_rule variable).

Using strings is just a temporary solution - on the long term, I want to 
use rule objects everywhere. 

Even if I initially didn't want to do it now, I thought about it again 
and changed the code to use rule objects.

This means two lines to initialize the rule object - one to create the 
object and a call to the newly added set_param() function (no, I don't 
want to do that in __init__)

> > @@ -4408,19 +4373,20 @@
> > 
> >      return 0
> >  
> >  def profile_known_capability(profile, capname):
> > -    if profile['deny']['capability'][capname].get('set', False):
> > -        return -1
> > +    rule = capability_rule()
> > +    rule.set_raw('capability %s,' % capname)  # having a
> > capability_rule object as parameter would be even better ;-)
> Or, you know, have the initializer for the class take an optional
> (or maybe not even optional) capname argument.

See above - it's now using CapabilityRule set_param().

Besides that, I implemented the is_known_rule() function that will work 
for all rule types, and replaces profile_known_capability()

I also added a match_includes() function so that we can search for 
possible include files with a rule object. This function replaces 
match_cap_includes() (for aa.py usage), however aa-mergeprof still needs 
match_cap_includes() so I rewrote it as a wrapper for match_includes().

I also simplified the type check at various places - checking with
    aa[profile][hat].get(rule_type, False)
also works - and has the advantage that it doesn't restrict the 
functions to capability rule objects.

> > === modified file 'utils/apparmor/cleanprofile.py'
> > --- utils/apparmor/cleanprofile.py  2014-09-05 21:21:00 +0000
> > +++ utils/apparmor/cleanprofile.py  2014-11-15 18:48:23 +0000
> > @@ -65,8 +65,8 @@
> > 
> >                  deleted +=
> >                  apparmor.aa.delete_duplicates(self.other.aa[progra
> >                  m][hat], inc)>              
> >              #Clean the duplicates of caps in other profile
> > 
> > -            deleted +=
> > delete_cap_duplicates(self.profile.aa[program][hat]['allow']['capab
> > ility'], self.other.aa[program][hat]['allow']['capability'],
> > self.same_file) -            deleted +=
> > delete_cap_duplicates(self.profile.aa[program][hat]['deny']['capabi
> > lity'], self.other.aa[program][hat]['deny']['capability'],
> > self.same_file) +            if self.same_file:
> > +                deleted +=
> > self.other.aa[program][hat]['capability'].delete_duplicates(self.pr
> > ofile.aa[program][hat]['capability'])
> Doesn't this need the same type check, to make sure that
> self.other.aa[program][hat]['capability'] is not None?

It didn't explode while I tested it, so I'd guess "no" ;-)


That all said - patch v3 is attached.

Line counts:
v3-1-add-base-and-capability-rule-class.diff - 374 lines added, 0 
removed
v3-2-add-capability-rule-test.diff - 791 lines added, 0 removed
v3-3-use-capability-rule-class.diff - 77 lines added, 111 removed


Regards,

Christian Boltz
-- 
Aus der Beschreibung entnehme ich, daß deine Fonts nach Typ 3
konvertiert werden (Finger im Hals) und deine Bilder auf Screen-
Qualität (Fuß zum Finger dazusteck...)     [Ratti in suse-linux]
--- v2-utils/apparmor/aa.py	2014-11-21 21:37:58.737863418 +0100
+++ utils/apparmor/aa.py	2014-11-22 22:34:43.781174768 +0100
@@ -400,6 +401,7 @@ def get_inactive_profile(local_profile):
 
 def create_new_profile(localfile, is_stub=False):
     local_profile = hasher()
+    ### INIT_PROFILE ###
     local_profile[localfile]['flags'] = 'complain'
     local_profile[localfile]['include']['abstractions/base'] = 1
 
@@ -438,6 +440,7 @@ def create_new_profile(localfile, is_stu
     for hatglob in cfg['required_hats'].keys():
         if re.search(hatglob, localfile):
             for hat in sorted(cfg['required_hats'][hatglob].split()):
+                ### INIT_PROFILE ###
                 local_profile[hat]['flags'] = 'complain'
 
     if not is_stub:
@@ -1028,6 +1031,7 @@ def handle_children(profile, hat, root):
 
                 if ans == 'CMD_ADDHAT':
                     hat = uhat
+                    ### INIT_PROFILE ###
                     aa[profile][hat]['flags'] = aa[profile][profile]['flags']
                 elif ans == 'CMD_USEDEFAULT':
                     hat = default_hat
@@ -2655,6 +2659,7 @@ def parse_profile_data(data, file, do_in
                 else:
                     hat = None
                 in_contained_hat = False
+                ### INIT_PROFILE ### (or save "external" to temp variable)
                 if hat:
                     profile_data[profile][hat]['external'] = True
                 else:
@@ -2667,6 +2672,7 @@ def parse_profile_data(data, file, do_in
             profile = strip_quotes(profile)
             if hat:
                 hat = strip_quotes(hat)
+            ### INIT_PROFILE ###
             # save profile name and filename
             profile_data[profile][hat]['name'] = profile
             profile_data[profile][hat]['filename'] = file
@@ -2706,7 +2712,7 @@ def parse_profile_data(data, file, do_in
             else:
                 parsed_profiles.append(profile)
                 profile = None
-
+                ### INIT_PROFILE ###
             initial_comment = ''
 
         elif RE_PROFILE_CAP.search(line):
=== modified file 'utils/apparmor/aa.py'
--- utils/apparmor/aa.py	2014-11-15 11:51:24 +0000
+++ utils/apparmor/aa.py	2014-11-22 23:35:20 +0000
@@ -52,6 +52,8 @@
 
 import apparmor.rules as aarules
 
+from apparmor.rule.capability import CapabilityRuleset, CapabilityRule
+
 from apparmor.yasti import SendDataToYast, GetDataFromYast, shutdown_yast
 
 # setup module translations
@@ -89,7 +91,7 @@
 # To store the globs entered by users so they can be provided again
 user_globs = []
 
-# The key for representing bare rules such as "capability," or "file,"
+# The key for representing bare "file," rules
 ALL = '\0ALL'
 
 ## Variables used under logprof
@@ -1549,13 +1551,15 @@
             for hat in hats:
                 for capability in sorted(log_dict[aamode][profile][hat]['capability'].keys()):
                     # skip if capability already in profile
-                    if profile_known_capability(aa[profile][hat], capability):
+                    capability_obj = CapabilityRule()
+                    capability_obj.set_param(capability)
+                    if is_known_rule(aa[profile][hat], 'capability', capability_obj):
                         continue
                     # Load variables? Don't think so.
                     severity = sev_db.rank('CAP_%s' % capability)
                     default_option = 1
                     options = []
-                    newincludes = match_cap_includes(aa[profile][hat], capability)
+                    newincludes = match_includes(aa[profile][hat], 'capability', capability_obj)
                     q = aaui.PromptQuestion()
 
                     if newincludes:
@@ -1628,16 +1632,22 @@
                                 if deleted:
                                     aaui.UI_Info(_('Deleted %s previous matching profile entries.') % deleted)
 
-                            aa[profile][hat]['allow']['capability'][capability]['set'] = True
-                            aa[profile][hat]['allow']['capability'][capability]['audit'] = audit_toggle
+                            else:
+                                capability_obj = CapabilityRule()
+                                capability_obj.set_param(capability, audit=audit)
+                                #aa[profile][hat]['capability'].add_raw('%s capability %s,'% (audit, capability))  # XXX yes, ugly ;-)
+                                aa[profile][hat]['capability'].add_obj(capability_obj)
+                                aaui.UI_Info(_('Adding capability %s to profile.') % capability)
 
                             changed[profile] = True
 
-                            aaui.UI_Info(_('Adding capability %s to profile.') % capability)
                             done = True
 
                         elif ans == 'CMD_DENY':
-                            aa[profile][hat]['deny']['capability'][capability]['set'] = True
+                            #aa[profile][hat]['capability'].add_raw('%s deny capability %s,'% (audit, capability))  # XXX yes, ugly ;-)
+                            capability_obj = CapabilityRule()
+                            capability_obj.set_param(capability, audit=audit, deny=True)
+                            aa[profile][hat]['capability'].add_obj(capability_obj)
                             changed[profile] = True
 
                             aaui.UI_Info(_('Denying capability %s to profile.') % capability)
@@ -2121,20 +2131,6 @@
                         deleted += 1
     return deleted
 
-def delete_cap_duplicates(profilecaps, inccaps):
-    deleted = []
-    if profilecaps and inccaps:
-        for capname in profilecaps.keys():
-            # XXX The presence of a bare capability rule ("capability,") should
-            #     cause more specific capability rules
-            #     ("capability audit_control,") to be deleted
-            if inccaps[capname].get('set', False) == 1:
-                deleted.append(capname)
-        for capname in deleted:
-            profilecaps.pop(capname)
-
-    return len(deleted)
-
 def delete_path_duplicates(profile, incname, allow):
     deleted = []
     for entry in profile[allow]['path'].keys():
@@ -2161,9 +2157,7 @@
 
         deleted += delete_net_duplicates(profile['deny']['netdomain'], include[incname][incname]['deny']['netdomain'])
 
-        deleted += delete_cap_duplicates(profile['allow']['capability'], include[incname][incname]['allow']['capability'])
-
-        deleted += delete_cap_duplicates(profile['deny']['capability'], include[incname][incname]['deny']['capability'])
+        deleted += profile['capability'].delete_duplicates(include[incname][incname]['capability'])
 
         deleted += delete_path_duplicates(profile, incname, 'allow')
         deleted += delete_path_duplicates(profile, incname, 'deny')
@@ -2173,9 +2167,7 @@
 
         deleted += delete_net_duplicates(profile['deny']['netdomain'], filelist[incname][incname]['deny']['netdomain'])
 
-        deleted += delete_cap_duplicates(profile['allow']['capability'], filelist[incname][incname]['allow']['capability'])
-
-        deleted += delete_cap_duplicates(profile['deny']['capability'], filelist[incname][incname]['deny']['capability'])
+        deleted += profile['capability'].delete_duplicates(filelist[incname][incname]['capability'])
 
         deleted += delete_path_duplicates(profile, incname, 'allow')
         deleted += delete_path_duplicates(profile, incname, 'deny')
@@ -2204,9 +2196,17 @@
     return False
 
 def match_cap_includes(profile, cap):
+    # still used by aa-mergeprof
+    capability_obj = CapabilityRule()
+    capability_obj.set_param(cap)
+    return match_includes(profile, 'capability', capability_obj)
+
+def match_includes(profile, rule_type, rule_obj):
     newincludes = []
     for incname in include.keys():
-        if valid_include(profile, incname) and include[incname][incname]['allow']['capability'][cap].get('set', False) == 1:
+        # XXX type check should go away once we init all profiles correctly
+        # XXX using a CapabilityRule object instead of is_raw_covered() might be nice/faster
+        if valid_include(profile, incname) and include[incname][incname].get(rule_type, False) and include[incname][incname][rule_type].is_obj_covered(rule_obj):
             newincludes.append(incname)
 
     return newincludes
@@ -2516,7 +2516,8 @@
 
                 for capability in prelog[aamode][profile][hat]['capability'].keys():
                     # If capability not already in profile
-                    if not aa[profile][hat]['allow']['capability'][capability].get('set', False):
+                    # XXX remove first check when we have proper profile initialisation
+                    if aa[profile][hat].get('capability', False) and not aa[profile][hat]['capability'].is_raw_covered("capability %s," % capability):
                         log_dict[aamode][profile][hat]['capability'][capability] = True
 
                 nd = prelog[aamode][profile][hat]['netdomain']
@@ -2704,6 +2705,10 @@
                 profile_data[profile][profile]['repo']['url'] = repo_data['url']
                 profile_data[profile][profile]['repo']['user'] = repo_data['user']
 
+            # init rule classes (if not done yet)
+            if not profile_data[profile][hat].get('capability', False):
+                profile_data[profile][hat]['capability'] = CapabilityRuleset()
+
         elif RE_PROFILE_END.search(line):
             # If profile ends and we're not in one
             if not profile:
@@ -2719,21 +2724,14 @@
             initial_comment = ''
 
         elif RE_PROFILE_CAP.search(line):
-            matches = RE_PROFILE_CAP.search(line)
-
             if not profile:
                 raise AppArmorException(_('Syntax Error: Unexpected capability entry found in file: %(file)s line: %(line)s') % { 'file': file, 'line': lineno + 1 })
 
-            audit, allow, allow_keyword, comment = parse_audit_allow(matches)
-            # TODO: honor allow_keyword and comment
-
-            capability = ALL
-            if matches.group('capability'):
-                capability = matches.group('capability').strip()
-                # TODO: can contain more than one capability- split it?
-
-            profile_data[profile][hat][allow]['capability'][capability]['set'] = True
-            profile_data[profile][hat][allow]['capability'][capability]['audit'] = audit
+            # init rule class (if not done yet)
+            if not profile_data[profile][hat].get('capability', False):
+                profile_data[profile][hat]['capability'] = CapabilityRuleset()
+
+            profile_data[profile][hat]['capability'].add_raw(line)
 
         elif RE_PROFILE_LINK.search(line):
             matches = RE_PROFILE_LINK.search(line).groups()
@@ -3373,29 +3371,8 @@
 def write_list_vars(prof_data, depth):
     return write_pair(prof_data, depth, '', 'lvar', '', ' = ', '', var_transform)
 
-def write_cap_rules(prof_data, depth, allow):
-    pre = '  ' * depth
-    data = []
-    allowstr = set_allow_str(allow)
-
-    if prof_data[allow].get('capability', False):
-        for cap in sorted(prof_data[allow]['capability'].keys()):
-            audit = ''
-            if prof_data[allow]['capability'][cap].get('audit', False):
-                audit = 'audit '
-            if prof_data[allow]['capability'][cap].get('set', False):
-                if cap == ALL:
-                    data.append('%s%s%scapability,' % (pre, audit, allowstr))
-                else:
-                    data.append('%s%s%scapability %s,' % (pre, audit, allowstr, cap))
-        data.append('')
-
-    return data
-
 def write_capabilities(prof_data, depth):
-    #data = write_single(prof_data, depth, '', 'set_capability', 'set capability ', ',')
-    data = write_cap_rules(prof_data, depth, 'deny')
-    data += write_cap_rules(prof_data, depth, 'allow')
+    data = prof_data['capability'].get_clean(depth)
     return data
 
 def write_net_rules(prof_data, depth, allow):
@@ -3886,6 +3863,8 @@
                                 write_prof_data[name]['allow'].pop(segs)
                             if write_prof_data[name]['deny'].get(segs, False):
                                 write_prof_data[name]['deny'].pop(segs)
+                            if write_prof_data[name].get(segs, False):
+                                write_prof_data[name][segs].delete_all_rules()
 
                     # then write everything else
                     for segs in default_write_order:
@@ -3927,25 +3906,7 @@
                     profile = None
 
             elif RE_PROFILE_CAP.search(line):
-                matches = RE_PROFILE_CAP.search(line).groups()
-                audit = False
-                if matches[0]:
-                    audit = matches[0]
-
-                allow = 'allow'
-                if matches[1] and matches[1].strip() == 'deny':
-                    allow = 'deny'
-
-                capability = ALL
-                if matches[2]:
-                    capability = matches[2].strip()
-
-                if not write_prof_data[hat][allow]['capability'][capability].get('set', False):
-                    correct = False
-                if not write_prof_data[hat][allow]['capability'][capability].get(audit, False) == audit:
-                    correct = False
-
-                if correct:
+                if write_prof_data[hat]['capability'].is_raw_covered(line, True, True):
                     if not segments['capability'] and True in segments.values():
                         for segs in list(filter(lambda x: segments[x], segments.keys())):
                             depth = len(line) - len(line.lstrip())
@@ -3955,13 +3916,11 @@
                                 write_prof_data[name]['allow'].pop(segs)
                             if write_prof_data[name]['deny'].get(segs, False):
                                 write_prof_data[name]['deny'].pop(segs)
+                            if write_prof_data[name].get(segs, False):
+                                write_prof_data[name][segs].delete_all_rules()
                     segments['capability'] = True
-                    write_prof_data[hat][allow]['capability'].pop(capability)
+                    write_prof_data[hat]['capability'].delete_raw(line)
                     data.append(line)
-
-                    #write_prof_data[hat][allow]['capability'][capability].pop(audit)
-
-                    #Remove this line
                 else:
                     # To-Do
                     pass
@@ -3996,6 +3955,8 @@
                                 write_prof_data[name]['allow'].pop(segs)
                             if write_prof_data[name]['deny'].get(segs, False):
                                 write_prof_data[name]['deny'].pop(segs)
+                            if write_prof_data[name].get(segs, False):
+                                write_prof_data[name][segs].delete_all_rules()
                     segments['link'] = True
                     write_prof_data[hat][allow]['link'].pop(link)
                     data.append(line)
@@ -4020,6 +3981,8 @@
                                 write_prof_data[name]['allow'].pop(segs)
                             if write_prof_data[name]['deny'].get(segs, False):
                                 write_prof_data[name]['deny'].pop(segs)
+                            if write_prof_data[name].get(segs, False):
+                                write_prof_data[name][segs].delete_all_rules()
                     segments['change_profile'] = True
                     write_prof_data[hat]['change_profile'].pop(cp)
                     data.append(line)
@@ -4050,6 +4013,8 @@
                                 write_prof_data[name]['allow'].pop(segs)
                             if write_prof_data[name]['deny'].get(segs, False):
                                 write_prof_data[name]['deny'].pop(segs)
+                            if write_prof_data[name].get(segs, False):
+                                write_prof_data[name][segs].delete_all_rules()
                     segments['alias'] = True
                     if profile:
                         write_prof_data[hat]['alias'].pop(from_name)
@@ -4079,6 +4044,8 @@
                                 write_prof_data[name]['allow'].pop(segs)
                             if write_prof_data[name]['deny'].get(segs, False):
                                 write_prof_data[name]['deny'].pop(segs)
+                            if write_prof_data[name].get(segs, False):
+                                write_prof_data[name][segs].delete_all_rules()
                     segments['rlimit'] = True
                     write_prof_data[hat]['rlimit'].pop(from_name)
                     data.append(line)
@@ -4104,6 +4071,8 @@
                                 write_prof_data[name]['allow'].pop(segs)
                             if write_prof_data[name]['deny'].get(segs, False):
                                 write_prof_data[name]['deny'].pop(segs)
+                            if write_prof_data[name].get(segs, False):
+                                write_prof_data[name][segs].delete_all_rules()
                     segments['lvar'] = True
                     write_prof_data[hat]['lvar'].pop(bool_var)
                     data.append(line)
@@ -4135,6 +4104,8 @@
                                 write_prof_data[name]['allow'].pop(segs)
                             if write_prof_data[name]['deny'].get(segs, False):
                                 write_prof_data[name]['deny'].pop(segs)
+                            if write_prof_data[name].get(segs, False):
+                                write_prof_data[name][segs].delete_all_rules()
                     segments['lvar'] = True
                     if profile:
                         write_prof_data[hat]['lvar'].pop(list_var)
@@ -4173,6 +4144,8 @@
                                 write_prof_data[name]['allow'].pop(segs)
                             if write_prof_data[name]['deny'].get(segs, False):
                                 write_prof_data[name]['deny'].pop(segs)
+                            if write_prof_data[name].get(segs, False):
+                                write_prof_data[name][segs].delete_all_rules()
                     segments['path'] = True
                     write_prof_data[hat][allow]['path'].pop(ALL)
                     data.append(line)
@@ -4221,6 +4194,8 @@
                                 write_prof_data[name]['allow'].pop(segs)
                             if write_prof_data[name]['deny'].get(segs, False):
                                 write_prof_data[name]['deny'].pop(segs)
+                            if write_prof_data[name].get(segs, False):
+                                write_prof_data[name][segs].delete_all_rules()
                     segments['path'] = True
                     write_prof_data[hat][allow]['path'].pop(path)
                     data.append(line)
@@ -4241,6 +4216,8 @@
                                     write_prof_data[name]['allow'].pop(segs)
                                 if write_prof_data[name]['deny'].get(segs, False):
                                     write_prof_data[name]['deny'].pop(segs)
+                                if write_prof_data[name].get(segs, False):
+                                    write_prof_data[name][segs].delete_all_rules()
                             segments['include'] = True
                         write_prof_data[hat]['include'].pop(include_name)
                         data.append(line)
@@ -4294,6 +4271,8 @@
                                 write_prof_data[name]['allow'].pop(segs)
                             if write_prof_data[name]['deny'].get(segs, False):
                                 write_prof_data[name]['deny'].pop(segs)
+                            if write_prof_data[name].get(segs, False):
+                                write_prof_data[name][segs].delete_all_rules()
                     segments['netdomain'] = True
 
             elif RE_PROFILE_CHANGE_HAT.search(line):
@@ -4407,20 +4386,18 @@
 
     return 0
 
-def profile_known_capability(profile, capname):
-    if profile['deny']['capability'][capname].get('set', False):
-        return -1
-
-    if profile['allow']['capability'][capname].get('set', False):
-        return 1
+def is_known_rule(profile, rule_type, rule_obj):
+    # XXX get rid of get() checks after we have a proper function to initialize a profile
+    if profile.get(rule_type, False):
+        if profile[rule_type].is_obj_covered(rule_obj, False):
+            return True
 
     for incname in profile['include'].keys():
-        if include[incname][incname]['deny']['capability'][capname].get('set', False):
-            return -1
-        if include[incname][incname]['allow']['capability'][capname].get('set', False):
-            return 1
+        if include[incname][incname].get(rule_type, False):
+            if include[incname][incname][rule_type].is_obj_covered(rule_obj, False):
+                return True
 
-    return 0
+    return False
 
 def profile_known_network(profile, family, sock_type):
     if netrules_access_check(profile['deny']['netdomain'], family, sock_type):

=== modified file 'utils/apparmor/cleanprofile.py'
--- utils/apparmor/cleanprofile.py	2014-09-05 21:21:00 +0000
+++ utils/apparmor/cleanprofile.py	2014-11-21 19:08:06 +0000
@@ -65,8 +65,8 @@
                 deleted += apparmor.aa.delete_duplicates(self.other.aa[program][hat], inc)
 
             #Clean the duplicates of caps in other profile
-            deleted += delete_cap_duplicates(self.profile.aa[program][hat]['allow']['capability'], self.other.aa[program][hat]['allow']['capability'], self.same_file)
-            deleted += delete_cap_duplicates(self.profile.aa[program][hat]['deny']['capability'], self.other.aa[program][hat]['deny']['capability'], self.same_file)
+            if self.same_file:
+                deleted += self.other.aa[program][hat]['capability'].delete_duplicates(self.profile.aa[program][hat]['capability'])
 
             #Clean the duplicates of path in other profile
             deleted += delete_path_duplicates(self.profile.aa[program][hat], self.other.aa[program][hat], 'allow', self.same_file)
@@ -108,17 +108,6 @@
 
     return len(deleted)
 
-def delete_cap_duplicates(profilecaps, profilecaps_other, same_profile=True):
-    deleted = []
-    if profilecaps and profilecaps_other and not same_profile:
-        for capname in profilecaps.keys():
-            if profilecaps_other[capname].get('set', False):
-                deleted.append(capname)
-        for capname in deleted:
-            profilecaps_other.pop(capname)
-
-    return len(deleted)
-
 def delete_net_duplicates(netrules, netrules_other, same_profile=True):
     deleted = 0
     hasher_obj = apparmor.aa.hasher()

-- 
AppArmor mailing list
[email protected]
Modify settings or unsubscribe at: 
https://lists.ubuntu.com/mailman/listinfo/apparmor

Reply via email to