Hello, aa-mergeprof still used the old aa[profile][hat][allow]['capability'] which no longer gets populated - which resulted in not asking for merging any capabilities.
Actually (and funnily), - if other.aa[profile][hat].get(allow, False): - continue resulted in never merging capability rules even before the change to CapabilityRule(set) - this was meant as optimization, but a "not" was missing in the condition ;-) so it always skipped capability rules. The patch changes ask_the_question to the CapabilityRule(set) layout. Besides that, - include the audit and deny keywords in the "Capability" headline (I'd prefer to just use the get_clean() rule, but that's another topic) - hide "(A)llow" when merging a deny rule - don't ask for capabilities that are already covered Also delete match_cap_includes() from aa.py, which is no longer used. I tested all changes manually. Note: getting the severity is a candidate to move into the *Rule classes, but first we have to disentangle how sev_db gets filled (or just pass the sev_db object as parameter?) The whole handling of getting and handling the user response is also a candidate for a function that can be used for more rule types. Oh, and finally merging (most parts of) aa-logprof and aa-mergeprof would be nice ;-) [ 06-mergeprof-capability-rule.diff ] === modified file utils/aa-mergeprof --- utils/aa-mergeprof 2015-01-30 21:07:51.234871116 +0100 +++ utils/aa-mergeprof 2015-05-14 01:54:03.572822464 +0200 @@ -308,32 +308,51 @@ return #Add the capabilities - for allow in ['allow', 'deny']: - if other.aa[profile][hat].get(allow, False): - continue - for capability in sorted(other.aa[profile][hat][allow]['capability'].keys()): - severity = sev_db.rank('CAP_%s' % capability) + if other.aa[profile][hat].get('capability', False): # (in theory) superflous check, but it avoids large whitespace changes ;-) + for cap_obj in other.aa[profile][hat]['capability'].rules: + + if self.user.aa[profile][hat]['capability'].is_covered(cap_obj): + continue + + if cap_obj.all_caps: + severity = 10 + cap_txt = 'ALL' + else: + cap_txt = ' '.join(cap_obj.capability) + severity = 0 + for cap in cap_obj.capability: + severity = max(severity, sev_db.rank('CAP_%s' % cap)) + + if cap_obj.deny: + cap_txt = 'deny %s' % cap_txt + + if cap_obj.audit: + cap_txt = 'audit %s' % cap_txt + default_option = 1 options = [] - newincludes = apparmor.aa.match_cap_includes(self.user.aa[profile][hat], capability) + newincludes = apparmor.aa.match_includes(self.user.aa[profile][hat], 'capability', cap_obj) q = aaui.PromptQuestion() if newincludes: options += list(map(lambda inc: '#include <%s>' %inc, sorted(set(newincludes)))) if options: - options.append('capability %s' % capability) + options.append(cap_obj.get_clean()) q.options = options q.selected = default_option - 1 q.headers = [_('Profile'), apparmor.aa.combine_name(profile, hat)] - q.headers += [_('Capability'), capability] + q.headers += [_('Capability'), cap_txt] q.headers += [_('Severity'), severity] audit_toggle = 0 - q.functions = ['CMD_ALLOW', 'CMD_DENY', 'CMD_IGNORE_ENTRY', 'CMD_ABORT', 'CMD_FINISHED'] + q.functions = [] + if not cap_obj.deny: + q.functions += ['CMD_ALLOW'] + q.functions += ['CMD_DENY', 'CMD_IGNORE_ENTRY', 'CMD_ABORT', 'CMD_FINISHED'] - q.default = 'CMD_ALLOW' + q.default = q.functions[0] done = False while not done: @@ -361,19 +380,20 @@ if deleted: aaui.UI_Info(_('Deleted %s previous matching profile entries.') % deleted) - self.user.aa[profile][hat]['allow']['capability'][capability]['set'] = True - self.user.aa[profile][hat]['allow']['capability'][capability]['audit'] = other.aa[profile][hat]['allow']['capability'][capability]['audit'] + self.user.aa[profile][hat]['capability'].add(cap_obj) apparmor.aa.changed[profile] = True - aaui.UI_Info(_('Adding capability %s to profile.'), capability) + aaui.UI_Info(_('Adding %s to profile.') % cap_obj.get_clean()) done = True elif ans == 'CMD_DENY': - self.user.aa[profile][hat]['deny']['capability'][capability]['set'] = True + cap_obj.deny = True + cap_obj.raw_rule = None # reset raw rule after manually modifying cap_obj + self.user.aa[profile][hat]['capability'].add(cap_obj) apparmor.aa.changed[profile] = True - aaui.UI_Info(_('Denying capability %s to profile.') % capability) + aaui.UI_Info(_('Adding %s to profile.') % cap_obj.get_clean()) done = True else: done = False === modified file utils/apparmor/aa.py --- utils/apparmor/aa.py 2015-05-13 23:15:05.146827969 +0200 +++ utils/apparmor/aa.py 2015-05-14 01:51:45.582085900 +0200 @@ -2154,11 +2154,6 @@ return match_includes(incname, 'network', network_obj) -def match_cap_includes(profile, capability): - # still used by aa-mergeprof - capability_obj = CapabilityRule(capability) - return match_includes(profile, 'capability', capability_obj) - def match_includes(profile, rule_type, rule_obj): newincludes = [] for incname in include.keys(): Regards, Christian Boltz -- > Rechte Maustaste auf den Mülleimer -> Mülleimer lehren Also, wenn Du dem Muelleimer 'was lehren kannst, bist Du echt gut. Ich hoffe, Du hast aber auch eine Lehrerausbildung, sonst kann das in die Hose gehn... :-) [> Manfred Tremmel und Thomas Hertweck in suse-linux] -- AppArmor mailing list AppArmor@lists.ubuntu.com Modify settings or unsubscribe at: https://lists.ubuntu.com/mailman/listinfo/apparmor