[apparmor] [patch] Change aa.py ask_the_questions() to use the aa-mergeprof code for capabilities
Christian Boltz
apparmor at cboltz.de
Mon May 25 09:50:47 UTC 2015
Hello,
Am Montag, 25. Mai 2015 schrieb Christian Boltz:
> [ 27-logprof-use-mergeprof-code-for-capability.diff ]
I should run "make check" more often :-/
I overlooked a "self.aa." (and didn't run into it in my manual tests),
so here's v2 with this fixed.
This patch replaces the code in aa.py ask_the_questions() that handles
capabilities with the ask_the_questions() code from aa-mergeprof.
This means to convert the capability log events to a CapabilityRuleset
stored in the (new) log_obj hasher, and then let the code from
aa-mergeprof operate on this hasher.
Most of the code after the "aa-mergeprof also has this code" comment is
a direct copy of the aa-mergeprof code, with the following changes:
- filter for profile mode (enforce/complain)
- set default button (allow or deny) based on profile mode
- keep seen_events counter happy (even if it isn't displayed anywhere)
- replace apparmor.aa.foo with just foo
The user interface is mostly unchanged, with two exceptions:
- options always displayed, even if there is only one option
- some slightly changed texts
BTW: I'm not sure if filtering and having different default buttons
based on the profile mode makes sense, except for "historical reasons".
Opinions?
[ 27-logprof-use-mergeprof-code-for-capability.diff ]
=== modified file utils/apparmor/aa.py
--- utils/apparmor/aa.py 2015-05-25 11:46:12.709387529 +0200
+++ utils/apparmor/aa.py 2015-05-25 11:46:08.085653465 +0200
@@ -1541,6 +1541,7 @@
def ask_the_questions():
found = 0
global seen_events
+ log_obj = hasher()
for aamode in sorted(log_dict.keys()):
# Describe the type of changes
if aamode == 'PERMITTING':
@@ -1564,106 +1565,107 @@
hats = [profile] + hats
for hat in hats:
+ if not log_obj[profile][hat].get('capability', False):
+ log_obj[profile][hat]['capability'] = CapabilityRuleset()
+
for capability in sorted(log_dict[aamode][profile][hat]['capability'].keys()):
- # skip if capability already in profile
- capability_obj = CapabilityRule(capability)
- if is_known_rule(aa[profile][hat], 'capability', capability_obj):
- continue
- # Load variables into sev_db? Not needed/used for capabilities.
- severity = capability_obj.severity(sev_db)
- default_option = 1
- options = []
- newincludes = match_includes(aa[profile][hat], 'capability', capability_obj)
- q = aaui.PromptQuestion()
+ capability_obj = CapabilityRule(capability, log_event=aamode)
+ log_obj[profile][hat]['capability'].add(capability_obj)
- if newincludes:
- options += list(map(lambda inc: '#include <%s>' % inc, sorted(set(newincludes))))
+ for ruletype in ['capability']:
+ # XXX aa-mergeprof also has this code - if you change it, keep aa-mergeprof in sync!
+ for rule_obj in log_obj[profile][hat][ruletype].rules:
+
+ if rule_obj.log_event != aamode: # XXX does it really make sense to handle enforce and complain mode changes in different rounds?
+ continue
+
+ if is_known_rule(aa[profile][hat], ruletype, rule_obj):
+ continue
+
+ default_option = 1
+ options = []
+ newincludes = match_includes(aa[profile][hat], ruletype, rule_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(rule_obj.get_clean())
q.options = options
q.selected = default_option - 1
- q.headers = [_('Profile'), combine_name(profile, hat)]
- q.headers += [_('Capability'), capability]
- q.headers += [_('Severity'), severity]
-
- audit_toggle = 0
- audit = ''
-
- q.functions = ['CMD_ALLOW', 'CMD_DENY', 'CMD_IGNORE_ENTRY', 'CMD_AUDIT_NEW',
- 'CMD_ABORT', 'CMD_FINISHED']
-
- # In complain mode: events default to allow
- # In enforce mode: events default to deny
- q.default = 'CMD_DENY'
- if aamode == 'PERMITTING':
- q.default = 'CMD_ALLOW'
-
- seen_events += 1
-
- done = False
- while not done:
- ans, selected = q.promptUser()
-
- if ans == 'CMD_FINISHED':
- save_profiles()
- return
-
- # Ignore the log entry
- if ans == 'CMD_IGNORE_ENTRY':
- done = True
- break
-
- if ans.startswith('CMD_AUDIT'):
- audit_toggle = not audit_toggle
- if audit_toggle:
- audit = 'audit '
- audit_cmd = 'CMD_AUDIT_OFF'
- else:
- audit = ''
- audit_cmd = 'CMD_AUDIT_NEW'
+ seen_events += 1
- q.functions = ['CMD_ALLOW', 'CMD_DENY', 'CMD_IGNORE_ENTRY', audit_cmd,
- 'CMD_ABORT', 'CMD_FINISHED', ]
+ done = False
+ while not done:
+ q.headers = [_('Profile'), combine_name(profile, hat)]
+ q.headers += rule_obj.logprof_header()
+
+ # Load variables into sev_db? Not needed/used for capabilities.
+ severity = rule_obj.severity(sev_db)
+ if severity != '--':
+ q.headers += [_('Severity'), severity]
+
+ q.functions = available_buttons(rule_obj)
+
+ # In complain mode: events default to allow
+ # In enforce mode: events default to deny
+ # XXX does this behaviour really make sense, except for "historical reasons"[tm]?
+ q.default = 'CMD_DENY'
+ if rule_obj.log_event == 'PERMITTING':
+ q.default = 'CMD_ALLOW'
+
+ ans, selected = q.promptUser()
+ if ans == 'CMD_IGNORE_ENTRY':
+ done = True
+ break
+
+ elif ans == 'CMD_FINISHED':
+ return
+
+ elif ans.startswith('CMD_AUDIT'):
+ if ans == 'CMD_AUDIT_NEW':
+ rule_obj.audit = True
+ rule_obj.raw_rule = None
+ else:
+ rule_obj.audit = False
+ rule_obj.raw_rule = None
+
+ options[len(options) - 1] = rule_obj.get_clean()
+ q.options = options
+
+ elif ans == 'CMD_ALLOW':
+ done = True
+ changed[profile] = True
- q.headers = [_('Profile'), combine_name(profile, hat),
- _('Capability'), audit + capability,
- _('Severity'), severity]
-
- if ans == 'CMD_ALLOW':
- selection = ''
- if options:
selection = options[selected]
- match = re_match_include(selection)
- if match:
- deleted = False
- inc = match # .groups()[0]
- deleted = delete_duplicates(aa[profile][hat], inc)
- aa[profile][hat]['include'][inc] = True
-
- aaui.UI_Info(_('Adding %s to profile.') % selection)
- if deleted:
- aaui.UI_Info(_('Deleted %s previous matching profile entries.') % deleted)
+
+ inc = re_match_include(selection)
+ if inc:
+ deleted = delete_duplicates(aa[profile][hat], inc)
+
+ aa[profile][hat]['include'][inc] = True
+
+ aaui.UI_Info(_('Adding %s to profile.') % selection)
+ if deleted:
+ aaui.UI_Info(_('Deleted %s previous matching profile entries.') % deleted)
+
+ else:
+ aa[profile][hat][ruletype].add(rule_obj)
+
+ aaui.UI_Info(_('Adding %s to profile.') % rule_obj.get_clean())
+
+ elif ans == 'CMD_DENY':
+ done = True
+ changed[profile] = True
+
+ rule_obj.deny = True
+ rule_obj.raw_rule = None # reset raw rule after manually modifying rule_obj
+ aa[profile][hat][ruletype].add(rule_obj)
+ aaui.UI_Info(_('Adding %s to profile.') % rule_obj.get_clean())
else:
- capability_obj = CapabilityRule(capability, audit=audit)
- aa[profile][hat]['capability'].add(capability_obj)
- aaui.UI_Info(_('Adding capability %s to profile.') % capability)
-
- changed[profile] = True
-
- done = True
-
- elif ans == 'CMD_DENY':
- capability_obj = CapabilityRule(capability, audit=audit, deny=True)
- aa[profile][hat]['capability'].add(capability_obj)
- changed[profile] = True
-
- aaui.UI_Info(_('Denying capability %s to profile.') % capability)
- done = True
- else:
- done = False
+ done = False
+ # END of code (mostly) shared with aa-mergeprof
# Process all the path entries.
for path in sorted(log_dict[aamode][profile][hat]['path'].keys()):
Regards,
Christian Boltz
--
When that limitation is removed, there might be a tendency that
for 12.2 the live image is 800MB, the next 1GB, next one 1.5GB.
If not careful we end up with a live-blu-ray, live-data-centre
or a live-cloud ;-)) [Hans Witvliet in opensuse-factory]
More information about the AppArmor
mailing list