[apparmor] [patch] Add support for signal log events to aa-logprof
John Johansen
john.johansen at canonical.com
Thu Nov 26 22:01:41 UTC 2015
On 10/23/2015 11:11 AM, Christian Boltz wrote:
> 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...)
you weren't kidding
> - 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.
>
>
I'm not fond of this. The translation is really ugly and the dict stuff
and hand_children() make me want to cry (bad memories of the perl code).
That said I didn't see anything wrong
Acked-by: John Johansen <john.johansen at canonical.com>
>
> [ 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
>
More information about the AppArmor
mailing list