← Back to team overview

apport-hackers team mailing list archive

[Merge] lp:~mdeslaur/apport/mac-profiles into lp:apport

 

Marc Deslauriers has proposed merging lp:~mdeslaur/apport/mac-profiles into lp:apport.

Requested reviews:
  Apport upstream developers (apport-hackers)

For more details, see:
https://code.launchpad.net/~mdeslaur/apport/mac-profiles/+merge/119520

This change allows specifying a list of profile names when using attach_mac_events() in hookutils.py.
This allows the apport hook for a package to be able to filter out apparmor events that pertained to the package itself.
-- 
https://code.launchpad.net/~mdeslaur/apport/mac-profiles/+merge/119520
Your team Apport upstream developers is requested to review the proposed merge of lp:~mdeslaur/apport/mac-profiles into lp:apport.
=== modified file 'NEWS'
--- NEWS	2012-08-03 07:28:07 +0000
+++ NEWS	2012-08-14 12:29:25 +0000
@@ -17,6 +17,8 @@
 Improvements:
  * Add an apport.memdbg() function which prints out current memory usage if
    APPORT_MEMDEBUG is set. Annotate apport-retrace with it.
+ * hookutils.py: Allow specifying a list of profile names when using
+   attach_mac_events().
 
 2.4 (2012-07-18):
 -----------------

=== modified file 'apport/hookutils.py'
--- apport/hookutils.py	2012-07-12 15:11:48 +0000
+++ apport/hookutils.py	2012-08-14 12:29:25 +0000
@@ -673,31 +673,58 @@
         'gutenprint-locales', 'system-config-printer-common', 'kdeprint')
 
 
-def attach_mac_events(report):
+def attach_mac_events(report, profiles=None):
     '''Attach MAC information and events to the report.'''
 
+    # Allow specifying a string, or a list of strings
+    if isinstance(profiles, str):
+        profiles = [profiles]
+
     mac_regex = 'audit\(|apparmor|selinux|security'
     mac_re = re.compile(mac_regex, re.IGNORECASE)
-    aa_denied_regex = 'apparmor="DENIED"'
-    aa_denied_re = re.compile(aa_denied_regex, re.IGNORECASE)
-
-    if os.path.exists('/var/log/kern.log'):
-        report['KernLog'] = recent_logfile('/var/log/kern.log', mac_re)
-    elif os.path.exists('/var/log/messages'):
-        report['KernLog'] = recent_logfile('/var/log/messages', mac_re)
-
-    if os.path.exists('/var/run/auditd.pid'):
+    aa_regex = 'apparmor="DENIED".+?profile=([^ ]+?)[ ]'
+    aa_re = re.compile(aa_regex, re.IGNORECASE)
+
+    if 'KernLog' not in report:
+        if os.path.exists('/var/log/kern.log'):
+            report['KernLog'] = recent_logfile('/var/log/kern.log', mac_re)
+        elif os.path.exists('/var/log/messages'):
+            report['KernLog'] = recent_logfile('/var/log/messages', mac_re)
+
+    if 'AuditLog' not in report and os.path.exists('/var/run/auditd.pid'):
         attach_root_command_outputs(report, {'AuditLog': 'egrep "' + mac_regex + '" /var/log/audit/audit.log'})
 
     attach_file(report, '/proc/version_signature', 'ProcVersionSignature')
     attach_file(report, '/proc/cmdline', 'ProcCmdline')
 
-    if re.search(aa_denied_re, report.get('KernLog', '')) or re.search(aa_denied_re, report.get('AuditLog', '')):
-        tags = report.get('Tags', '')
-        if tags:
-            tags += ' '
-        report['Tags'] = tags + 'apparmor'
-
+    for match in re.findall(aa_re, report.get('KernLog', '') + \
+                                   report.get('AuditLog', '')):
+
+        if not profiles:
+            _add_tag(report, 'apparmor')
+            break
+
+        try:
+            if match[0] == '"':
+                profile = match[1:-1]
+            elif sys.version[0] >= '3':
+                profile = bytes.fromhex(match).decode('UTF-8', errors='replace')
+            else:
+                profile = match.decode('hex', errors='replace')
+        except:
+            continue
+
+        for search_profile in profiles:
+            if re.match('^' + search_profile + '$', profile):
+                _add_tag(report, 'apparmor')
+                break
+
+def _add_tag(report, tag):
+    '''Adds or appends a tag to the report'''
+    current_tags = report.get('Tags', '')
+    if current_tags:
+        current_tags += ' '
+    report['Tags'] = current_tags + tag
 
 def attach_related_packages(report, packages):
     '''Attach version information for related packages

=== modified file 'test/test_hookutils.py'
--- test/test_hookutils.py	2012-06-13 08:10:40 +0000
+++ test/test_hookutils.py	2012-08-14 12:29:25 +0000
@@ -157,6 +157,138 @@
         self.assertEqual(apport.hookutils.recent_syslog(re.compile('ThisCantPossiblyHitAnything')), '')
         self.assertNotEqual(len(apport.hookutils.recent_syslog(re.compile('.'))), 0)
 
+    def test_attach_mac_events(self):
+        '''attach_mac_events()'''
+
+        denied_log = \
+            '[  351.624338] type=1400 audit(1343775571.688:27): apparmor="DENIED"' + \
+            ' operation="capable" parent=1 profile="/usr/sbin/cupsd" pid=1361' + \
+            ' comm="cupsd" pid=1361 comm="cupsd" capability=36  capname="block_suspend"\n'
+
+        denied_hex = \
+            '[  351.624338] type=1400 audit(1343775571.688:27): apparmor="DENIED"' + \
+            ' operation="capable" parent=1 profile=2F7573722F7362696E2F6375707364 pid=1361' + \
+            ' comm="cupsd" pid=1361 comm="cupsd" capability=36  capname="block_suspend"\n'
+
+        report = {}
+        apport.hookutils.attach_mac_events(report)
+        self.assertTrue('KernLog' in report)
+        self.assertFalse('Tags' in report)
+
+        # No AppArmor messages
+        report = {}
+        report['KernLog'] = \
+            "[    2.997534] i915 0000:00:02.0: power state changed by ACPI to D0\n" + \
+            "[    2.997541] i915 0000:00:02.0: PCI INT A -> GSI 16 (level, low)\n" + \
+            "[    2.997544] i915 0000:00:02.0: setting latency timer to 64\n" + \
+            "[    3.061584] i915 0000:00:02.0: irq 42 for MSI/MSI-X\n"
+
+        apport.hookutils.attach_mac_events(report)
+        self.assertFalse('Tags' in report)
+
+        # AppArmor message, but not a denial
+        report = {}
+        report['KernLog'] = \
+            '[   32.420248] type=1400 audit(1344562672.449:2): apparmor="STATUS"' + \
+            ' operation="profile_load" name="/sbin/dhclient" pid=894' + \
+            ' comm="apparmor_parser"\n'
+
+        apport.hookutils.attach_mac_events(report)
+        self.assertFalse('Tags' in report)
+
+        # AppArmor denial, empty tags, no profile specified
+        report = {}
+        report['KernLog'] = denied_log
+
+        apport.hookutils.attach_mac_events(report)
+        self.assertEqual(report['Tags'], 'apparmor')
+
+        # AppArmor hex-encoded denial, no profile specified
+        report = {}
+        report['KernLog'] =  denied_hex
+
+        apport.hookutils.attach_mac_events(report)
+        self.assertEqual(report['Tags'], 'apparmor')
+
+        # AppArmor denial in AuditLog
+        report = {}
+        report['AuditLog'] = denied_log
+
+        apport.hookutils.attach_mac_events(report)
+        self.assertEqual(report['Tags'], 'apparmor')
+
+        # AppArmor denial, pre-existing tags, no profile specified
+        report = {}
+        report['KernLog'] = denied_log
+        report['Tags'] = 'bogustag'
+
+        apport.hookutils.attach_mac_events(report)
+        self.assertEqual(report['Tags'], 'bogustag apparmor')
+
+        # AppArmor denial, single profile specified
+        report = {}
+        report['KernLog'] = denied_log
+
+        apport.hookutils.attach_mac_events(report, '/usr/sbin/cupsd')
+        self.assertEqual(report['Tags'], 'apparmor')
+
+        # AppArmor denial, regex profile specified
+        report = {}
+        report['KernLog'] = denied_log
+
+        apport.hookutils.attach_mac_events(report, '/usr/sbin/cups.*')
+        self.assertEqual(report['Tags'], 'apparmor')
+
+        # AppArmor denial, subset profile specified
+        report = {}
+        report['KernLog'] = denied_log
+
+        apport.hookutils.attach_mac_events(report, '/usr/sbin/cup')
+        self.assertFalse('Tags' in report)
+
+        # AppArmor hex-encoded denial, single profile specified
+        report = {}
+        report['KernLog'] = denied_hex
+
+        apport.hookutils.attach_mac_events(report, '/usr/sbin/cupsd')
+        self.assertEqual(report['Tags'], 'apparmor')
+
+        # AppArmor denial, single different profile specified
+        report = {}
+        report['KernLog'] = denied_log
+
+        apport.hookutils.attach_mac_events(report, '/usr/sbin/nonexistent')
+        self.assertFalse('Tags' in report)
+
+        # AppArmor denial, multiple profiles specified
+        report = {}
+        report['KernLog'] = denied_log
+        profiles = [ '/usr/bin/nonexistent', '/usr/sbin/cupsd' ]
+
+        apport.hookutils.attach_mac_events(report, profiles)
+        self.assertEqual(report['Tags'], 'apparmor')
+
+        # AppArmor denial, multiple different profiles
+        report = {}
+        report['KernLog'] = denied_log
+        profiles = [ '/usr/bin/nonexistent', '/usr/sbin/anotherone' ]
+
+        apport.hookutils.attach_mac_events(report, profiles)
+        self.assertFalse('Tags' in report)
+
+        # Multiple AppArmor denials, second match
+        report = {}
+        report['KernLog'] = \
+            '[  351.624338] type=1400 audit(1343775571.688:27): apparmor="DENIED"' + \
+            ' operation="capable" parent=1 profile="/usr/sbin/blah" pid=1361' + \
+            ' comm="cupsd" pid=1361 comm="cupsd" capability=36  capname="block_suspend"\n' + \
+            '[  351.624338] type=1400 audit(1343775571.688:27): apparmor="DENIED"' + \
+            ' operation="capable" parent=1 profile="/usr/sbin/cupsd" pid=1361' + \
+            ' comm="cupsd" pid=1361 comm="cupsd" capability=36  capname="block_suspend"\n'
+
+        apport.hookutils.attach_mac_events(report, '/usr/sbin/cupsd')
+        self.assertEqual(report['Tags'], 'apparmor')
+
     def test_recent_logfile_overflow(self):
         '''recent_logfile on a huge file'''