[apparmor] [patch] Add support for signal log events to aa-logprof

Christian Boltz apparmor at cboltz.de
Fri Oct 23 18:11:28 UTC 2015


Hello,

this patch adds support for signal log events to aa-logprof. 

In other words: this is the first new feature in aa-logprof since I'm 
working on the rule classes :-)

In detail, this means:
- handle signal events in logparser.py
- "translate" those events in aa.py - from log (logparser.py readlog())
  to prelog (handle_children()) to log_dict (collapse_log()) to
  log_obj (ask_the_questions())
  (yes, really! :-/ - needless to say that this is ugly...)
- finally ask the user about the signal in ask_the_questions()

Also add a logparser test to test-signal.py to ensure the logparser step
works as expected.

Note that the aa.py changes are not covered by tests, however they
worked in a manual test.



[ 12-logprof-signal.diff ]

=== modified file ./utils/apparmor/aa.py
--- utils/apparmor/aa.py        2015-10-23 17:27:29.601410816 +0200
+++ utils/apparmor/aa.py        2015-10-23 19:34:14.770163154 +0200
@@ -1125,6 +1126,16 @@
                     continue
                 prelog[aamode][profile][hat]['capability'][capability] = True
 
+            elif typ == 'signal':
+                # If signal then we (should) have pid, profile, hat, program, mode, access, signal and peer
+                pid, p, h, prog, aamode, access, signal, peer = entry
+                if not regex_nullcomplain.search(p) and not regex_nullcomplain.search(h):
+                    profile = p
+                    hat = h
+                if not profile or not hat:
+                    continue
+                prelog[aamode][profile][hat]['signal'][peer][access][signal] = True
+
             elif typ == 'path' or typ == 'exec':
                 # If path or exec then we (should) have pid, profile, hat, program, mode, details and to_name
                 pid, p, h, prog, aamode, mode, detail, to_name = entry[:8]
@@ -1629,7 +1640,14 @@
                         network_obj = NetworkRule(family, sock_type, log_event=aamode)
                         log_obj[profile][hat]['network'].add(network_obj)
 
-                for ruletype in ['capability', 'network']:
+
+                for peer in sorted(log_dict[aamode][profile][hat]['signal'].keys()):
+                    for access in sorted(log_dict[aamode][profile][hat]['signal'][peer].keys()):
+                        for signal in sorted(log_dict[aamode][profile][hat]['signal'][peer][access].keys()):
+                            signal_obj = SignalRule(access, signal, peer, log_event=aamode)
+                            log_obj[profile][hat]['signal'].add(signal_obj)
+
+                for ruletype in ['capability', 'network', 'signal']:
                     # 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:
 
@@ -2456,6 +2474,14 @@
                         if not is_known_rule(aa[profile][hat], 'network', NetworkRule(family, sock_type)):
                             log_dict[aamode][profile][hat]['netdomain'][family][sock_type] = True
 
+                sig = prelog[aamode][profile][hat]['signal']
+                for peer in sig.keys():
+                    for access in sig[peer].keys():
+                        for signal in sig[peer][access].keys():
+                            if not is_known_rule(aa[profile][hat], 'signal', SignalRule(access, signal, peer)):
+                                log_dict[aamode][profile][hat]['signal'][peer][access][signal] = True
+
+
 PROFILE_MODE_RE      = re.compile('^(r|w|l|m|k|a|ix|ux|px|pux|cx|pix|cix|cux|Ux|Px|PUx|Cx|Pix|Cix|CUx)+$')
 PROFILE_MODE_DENY_RE = re.compile('^(r|w|l|m|k|a|x)+$')
 
=== modified file ./utils/apparmor/logparser.py
--- utils/apparmor/logparser.py 2015-10-23 19:44:41.344399036 +0200
+++ utils/apparmor/logparser.py 2015-10-23 19:37:12.788718122 +0200
@@ -137,6 +137,10 @@
             ev['family'] = event.net_family
             ev['protocol'] = event.net_protocol
             ev['sock_type'] = event.net_sock_type
+        elif ev['operation'] and ev['operation'] == 'signal':
+            ev['signal'] = event.signal
+            ev['peer'] = event.peer
+
         LibAppArmor.free_record(event)
 
         if not ev['time']:
@@ -356,6 +360,9 @@
         elif e['operation'] == 'change_hat':
             return(e['pid'], e['parent'], 'unknown_hat',
                              [profile, hat, aamode, hat])
+        elif e['operation'] == 'signal':
+            return(e['pid'], e['parent'], 'signal',
+                             [profile, hat, prog, aamode, e['denied_mask'], e['signal'], e['peer']])
         else:
             self.debug_logger.debug('UNHANDLED: %s' % e)
 
=== modified file ./utils/test/test-signal.py
--- utils/test/test-signal.py   2015-10-23 19:44:41.344399036 +0200
+++ utils/test/test-signal.py   2015-10-23 19:40:17.146900973 +0200
@@ -20,7 +20,7 @@
 from apparmor.rule.signal import SignalRule, SignalRuleset
 from apparmor.rule import BaseRule
 from apparmor.common import AppArmorException, AppArmorBug
-#from apparmor.logparser import ReadLog
+from apparmor.logparser import ReadLog
 from apparmor.translations import init_translation
 _ = init_translation()
 
@@ -82,44 +84,43 @@
         with self.assertRaises(expected):
             SignalRule.parse(rawrule)
 
-#class SignalTestParseFromLog(SignalTest):
-#    def test_net_from_log(self):
-#        parser = ReadLog('', '', '', '', '')
-#        event = 'type=AVC msg=audit(1428699242.551:386): apparmor="DENIED" operation="create" profile="/bin/ping" pid=10589 comm="ping" family="send" sock_type="raw" protocol=1'
-
-#        parsed_event = parser.parse_event(event)
-
-#        self.assertEqual(parsed_event, {
-#            'request_mask': None,
-#            'denied_mask': None,
-#            'error_code': 0,
-#            'family': 'send',
-#            'magic_token': 0,
-#            'parent': 0,
-#            'profile': '/bin/ping',
-#            'protocol': 'icmp',
-#            'sock_type': 'raw',
-#            'operation': 'create',
-#            'resource': None,
-#            'info': None,
-#            'aamode': 'REJECTING',
-#            'time': 1428699242,
-#            'active_hat': None,
-#            'pid': 10589,
-#            'task': 0,
-#            'attr': None,
-#            'name2': None,
-#            'name': None,
-#        })
+class SignalTestParseFromLog(SignalTest):
+    def test_net_from_log(self):
+        parser = ReadLog('', '', '', '', '')
+        event = 'type=AVC msg=audit(1409438250.564:201): apparmor="DENIED" operation="signal" profile="/usr/bin/pulseaudio" pid=2531 comm="pulseaudio" requested_mask="send" denied_mask="send" signal=term peer="/usr/bin/pulseaudio///usr/lib/pulseaudio/pulse/gconf-helper"'
+
+        parsed_event = parser.parse_event(event)
+
+        self.assertEqual(parsed_event, {
+            'request_mask': 'send',
+            'denied_mask': 'send',
+            'error_code': 0,
+            'magic_token': 0,
+            'parent': 0,
+            'profile': '/usr/bin/pulseaudio',
+            'signal': 'term',
+            'peer': '/usr/bin/pulseaudio///usr/lib/pulseaudio/pulse/gconf-helper',
+            'operation': 'signal',
+            'resource': None,
+            'info': None,
+            'aamode': 'REJECTING',
+            'time': 1409438250,
+            'active_hat': None,
+            'pid': 2531,
+            'task': 0,
+            'attr': None,
+            'name2': None,
+            'name': None,
+        })
 
-#        obj = SignalRule(parsed_event['family'], parsed_event['sock_type'], log_event=parsed_event)
+        obj = SignalRule(parsed_event['denied_mask'], parsed_event['signal'], parsed_event['peer'], log_event=parsed_event)
 
-#        #              audit  allow  deny   comment        access    all?   type/proto  all?
-#        expected = exp(False, False, False, ''           , 'send',   False, 'raw'    , False)
+        #              audit  allow  deny   comment    access        all?   signal       all?   peer                                                           all?
+        expected = exp(False, False, False, '',        {'send'},     False, {'term'},    False, '/usr/bin/pulseaudio///usr/lib/pulseaudio/pulse/gconf-helper', False)
 
-#        self._compare_obj(obj, expected)
+        self._compare_obj(obj, expected)
 
-#        self.assertEqual(obj.get_raw(1), '  signal send raw,')
+        self.assertEqual(obj.get_raw(1), '  signal send set=term peer=/usr/bin/pulseaudio///usr/lib/pulseaudio/pulse/gconf-helper,')
 
 
 class SignalFromInit(SignalTest):



Regards,

Christian Boltz
-- 
Working in a datacentre is the next best thing to being talented and
popular. I get to spend hours surrounded by thousands of screaming fans
[http://twitter.com/_gmh_/status/80741758358654977]




More information about the AppArmor mailing list