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

Christian Boltz apparmor at cboltz.de
Mon Nov 23 23:38:26 UTC 2015


Hello,

this is the last patch directly related to introducing SignalRule that 
didn't get a review yet.

Can someone have a look at it, please? ;-)

If nobody objects, I'll commit it on Thursday as Acked-by <timeout>


Am Freitag, 23. Oktober 2015 schrieb Christian Boltz:
> 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|Pi
> x|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
-- 
Meeting, n.:
    An assembly of people coming together to decide what person or
    department not represented in the room must solve a problem.




More information about the AppArmor mailing list