From 5c26296b9f63d95f79498dec1d77406d81a04620 Mon Sep 17 00:00:00 2001 From: Christian Boltz Date: Tue, 6 Dec 2016 22:24:56 +0100 Subject: [PATCH] logparser.py: improve file vs. network event recognition Sometimes network events come with an operation keyword looking like file_perm which makes them look like file events. Instead of ignoring these events (which was a hotfix to avoid crashes), improve the type detection. In detail, this means: - replace OPERATION_TYPES (which was basically a list of network event keywords) with OP_TYPE_FILE_OR_NET (which is a list of keywords for file and network events) - change op_type() parameters to expect the whole event, not only the operation keyword, and rebuild the type detection based on the event details - as a side effect, this simplifies the detection for file event operations in parse_event_for_tree() - remove workaround code from parse_event_for_tree() Also add 4 new testcases with log messages that were ignored before. References: a) various bugreports about crashes caused by unexpected operation keywords: https://bugs.launchpad.net/apparmor/+bug/1466812 https://bugs.launchpad.net/apparmor/+bug/1509030 https://bugs.launchpad.net/apparmor/+bug/1540562 https://bugs.launchpad.net/apparmor/+bug/1577051 https://bugs.launchpad.net/apparmor/+bug/1582374 b) the summary bug for this patch https://bugs.launchpad.net/apparmor/+bug/1613061 Acked-by: Steve Beattie for trunk and 2.10. --- .../file_inherit_network_lp1509030.err | 0 .../file_inherit_network_lp1509030.in | 1 + .../file_inherit_network_lp1509030.out | 14 +++ .../file_inherit_network_lp1509030.profile | 4 + .../file_perm_network_lp1466812.err | 0 .../test_multi/file_perm_network_lp1466812.in | 1 + .../file_perm_network_lp1466812.out | 17 ++++ .../file_perm_network_lp1466812.profile | 4 + .../file_perm_network_receive_lp1577051.err | 0 .../file_perm_network_receive_lp1577051.in | 1 + .../file_perm_network_receive_lp1577051.out | 19 ++++ ...ile_perm_network_receive_lp1577051.profile | 7 ++ .../file_perm_network_receive_lp1582374.err | 0 .../file_perm_network_receive_lp1582374.in | 1 + .../file_perm_network_receive_lp1582374.out | 19 ++++ ...ile_perm_network_receive_lp1582374.profile | 7 ++ utils/apparmor/logparser.py | 96 ++++++++++--------- 17 files changed, 148 insertions(+), 43 deletions(-) create mode 100644 libraries/libapparmor/testsuite/test_multi/file_inherit_network_lp1509030.err create mode 100644 libraries/libapparmor/testsuite/test_multi/file_inherit_network_lp1509030.in create mode 100644 libraries/libapparmor/testsuite/test_multi/file_inherit_network_lp1509030.out create mode 100644 libraries/libapparmor/testsuite/test_multi/file_inherit_network_lp1509030.profile create mode 100644 libraries/libapparmor/testsuite/test_multi/file_perm_network_lp1466812.err create mode 100644 libraries/libapparmor/testsuite/test_multi/file_perm_network_lp1466812.in create mode 100644 libraries/libapparmor/testsuite/test_multi/file_perm_network_lp1466812.out create mode 100644 libraries/libapparmor/testsuite/test_multi/file_perm_network_lp1466812.profile create mode 100644 libraries/libapparmor/testsuite/test_multi/file_perm_network_receive_lp1577051.err create mode 100644 libraries/libapparmor/testsuite/test_multi/file_perm_network_receive_lp1577051.in create mode 100644 libraries/libapparmor/testsuite/test_multi/file_perm_network_receive_lp1577051.out create mode 100644 libraries/libapparmor/testsuite/test_multi/file_perm_network_receive_lp1577051.profile create mode 100644 libraries/libapparmor/testsuite/test_multi/file_perm_network_receive_lp1582374.err create mode 100644 libraries/libapparmor/testsuite/test_multi/file_perm_network_receive_lp1582374.in create mode 100644 libraries/libapparmor/testsuite/test_multi/file_perm_network_receive_lp1582374.out create mode 100644 libraries/libapparmor/testsuite/test_multi/file_perm_network_receive_lp1582374.profile diff --git a/libraries/libapparmor/testsuite/test_multi/file_inherit_network_lp1509030.err b/libraries/libapparmor/testsuite/test_multi/file_inherit_network_lp1509030.err new file mode 100644 index 000000000..e69de29bb diff --git a/libraries/libapparmor/testsuite/test_multi/file_inherit_network_lp1509030.in b/libraries/libapparmor/testsuite/test_multi/file_inherit_network_lp1509030.in new file mode 100644 index 000000000..26ddafa16 --- /dev/null +++ b/libraries/libapparmor/testsuite/test_multi/file_inherit_network_lp1509030.in @@ -0,0 +1 @@ +Oct 22 15:57:38 NR021AA kernel: [ 69.827705] audit: type=1400 audit(1445522258.769:1054): apparmor="DENIED" operation="file_inherit" profile="/usr/lib/NetworkManager/nm-dhcp-client.action" pid=2407 comm="nm-dhcp-client." lport=10580 family="inet6" sock_type="dgram" protocol=17 diff --git a/libraries/libapparmor/testsuite/test_multi/file_inherit_network_lp1509030.out b/libraries/libapparmor/testsuite/test_multi/file_inherit_network_lp1509030.out new file mode 100644 index 000000000..c7e297909 --- /dev/null +++ b/libraries/libapparmor/testsuite/test_multi/file_inherit_network_lp1509030.out @@ -0,0 +1,14 @@ +START +File: file_inherit_network_lp1509030.in +Event type: AA_RECORD_DENIED +Audit ID: 1445522258.769:1054 +Operation: file_inherit +Profile: /usr/lib/NetworkManager/nm-dhcp-client.action +Command: nm-dhcp-client. +PID: 2407 +Network family: inet6 +Socket type: dgram +Protocol: udp +Local port: 10580 +Epoch: 1445522258 +Audit subid: 1054 diff --git a/libraries/libapparmor/testsuite/test_multi/file_inherit_network_lp1509030.profile b/libraries/libapparmor/testsuite/test_multi/file_inherit_network_lp1509030.profile new file mode 100644 index 000000000..bdef4d493 --- /dev/null +++ b/libraries/libapparmor/testsuite/test_multi/file_inherit_network_lp1509030.profile @@ -0,0 +1,4 @@ +/usr/lib/NetworkManager/nm-dhcp-client.action { + network inet6 dgram, + +} diff --git a/libraries/libapparmor/testsuite/test_multi/file_perm_network_lp1466812.err b/libraries/libapparmor/testsuite/test_multi/file_perm_network_lp1466812.err new file mode 100644 index 000000000..e69de29bb diff --git a/libraries/libapparmor/testsuite/test_multi/file_perm_network_lp1466812.in b/libraries/libapparmor/testsuite/test_multi/file_perm_network_lp1466812.in new file mode 100644 index 000000000..36fe1f770 --- /dev/null +++ b/libraries/libapparmor/testsuite/test_multi/file_perm_network_lp1466812.in @@ -0,0 +1 @@ +Jun 19 12:00:55 piorun kernel: [4475115.459952] audit: type=1400 audit(1434708055.676:19629): apparmor="ALLOWED" operation="file_perm" profile="/usr/sbin/apache2" pid=3512 comm="apache2" laddr=::ffff:192.168.236.159 lport=80 faddr=::ffff:192.168.103.80 fport=61985 family="inet6" sock_type="stream" protocol=6 diff --git a/libraries/libapparmor/testsuite/test_multi/file_perm_network_lp1466812.out b/libraries/libapparmor/testsuite/test_multi/file_perm_network_lp1466812.out new file mode 100644 index 000000000..f94731a9a --- /dev/null +++ b/libraries/libapparmor/testsuite/test_multi/file_perm_network_lp1466812.out @@ -0,0 +1,17 @@ +START +File: file_perm_network_lp1466812.in +Event type: AA_RECORD_ALLOWED +Audit ID: 1434708055.676:19629 +Operation: file_perm +Profile: /usr/sbin/apache2 +Command: apache2 +PID: 3512 +Network family: inet6 +Socket type: stream +Protocol: tcp +Local addr: ::ffff:192.168.236.159 +Foreign addr: ::ffff:192.168.103.80 +Local port: 80 +Foreign port: 61985 +Epoch: 1434708055 +Audit subid: 19629 diff --git a/libraries/libapparmor/testsuite/test_multi/file_perm_network_lp1466812.profile b/libraries/libapparmor/testsuite/test_multi/file_perm_network_lp1466812.profile new file mode 100644 index 000000000..60e448b34 --- /dev/null +++ b/libraries/libapparmor/testsuite/test_multi/file_perm_network_lp1466812.profile @@ -0,0 +1,4 @@ +/usr/sbin/apache2 { + network inet6 stream, + +} diff --git a/libraries/libapparmor/testsuite/test_multi/file_perm_network_receive_lp1577051.err b/libraries/libapparmor/testsuite/test_multi/file_perm_network_receive_lp1577051.err new file mode 100644 index 000000000..e69de29bb diff --git a/libraries/libapparmor/testsuite/test_multi/file_perm_network_receive_lp1577051.in b/libraries/libapparmor/testsuite/test_multi/file_perm_network_receive_lp1577051.in new file mode 100644 index 000000000..49015a8d9 --- /dev/null +++ b/libraries/libapparmor/testsuite/test_multi/file_perm_network_receive_lp1577051.in @@ -0,0 +1 @@ +type=AVC msg=audit(1463403689.381:267599): apparmor="ALLOWED" operation="file_perm" profile="/usr/sbin/apache2//www.xxxxxxxxxx.co.uk" pid=13215 comm="apache2" laddr=::ffff:192.168.1.100 lport=80 faddr=::ffff:192.168.1.100 fport=45658 family="inet6" sock_type="stream" protocol=6 requested_mask="send" denied_mask="send" diff --git a/libraries/libapparmor/testsuite/test_multi/file_perm_network_receive_lp1577051.out b/libraries/libapparmor/testsuite/test_multi/file_perm_network_receive_lp1577051.out new file mode 100644 index 000000000..421dd4348 --- /dev/null +++ b/libraries/libapparmor/testsuite/test_multi/file_perm_network_receive_lp1577051.out @@ -0,0 +1,19 @@ +START +File: file_perm_network_receive_lp1577051.in +Event type: AA_RECORD_ALLOWED +Audit ID: 1463403689.381:267599 +Operation: file_perm +Mask: send +Denied Mask: send +Profile: /usr/sbin/apache2//www.xxxxxxxxxx.co.uk +Command: apache2 +PID: 13215 +Network family: inet6 +Socket type: stream +Protocol: tcp +Local addr: ::ffff:192.168.1.100 +Foreign addr: ::ffff:192.168.1.100 +Local port: 80 +Foreign port: 45658 +Epoch: 1463403689 +Audit subid: 267599 diff --git a/libraries/libapparmor/testsuite/test_multi/file_perm_network_receive_lp1577051.profile b/libraries/libapparmor/testsuite/test_multi/file_perm_network_receive_lp1577051.profile new file mode 100644 index 000000000..e44ef1a79 --- /dev/null +++ b/libraries/libapparmor/testsuite/test_multi/file_perm_network_receive_lp1577051.profile @@ -0,0 +1,7 @@ +/usr/sbin/apache2 { + + ^www.xxxxxxxxxx.co.uk { + network inet6 stream, + + } +} diff --git a/libraries/libapparmor/testsuite/test_multi/file_perm_network_receive_lp1582374.err b/libraries/libapparmor/testsuite/test_multi/file_perm_network_receive_lp1582374.err new file mode 100644 index 000000000..e69de29bb diff --git a/libraries/libapparmor/testsuite/test_multi/file_perm_network_receive_lp1582374.in b/libraries/libapparmor/testsuite/test_multi/file_perm_network_receive_lp1582374.in new file mode 100644 index 000000000..98c3fb906 --- /dev/null +++ b/libraries/libapparmor/testsuite/test_multi/file_perm_network_receive_lp1582374.in @@ -0,0 +1 @@ +Apr 30 21:53:05 nova kernel: [24668.960760] audit: type=1400 audit(1462045985.636:2154): apparmor="ALLOWED" operation="file_perm" profile="/usr/local/apache-tomcat-8.0.33/bin/catalina.sh///usr/local/jdk1.8.0_92/bin/java" pid=12529 comm="java" laddr=::ffff:127.0.0.1 lport=8080 faddr=::ffff:127.0.0.1 fport=52308 family="inet6" sock_type="stream" protocol=6 requested_mask="receive" denied_mask="receive" diff --git a/libraries/libapparmor/testsuite/test_multi/file_perm_network_receive_lp1582374.out b/libraries/libapparmor/testsuite/test_multi/file_perm_network_receive_lp1582374.out new file mode 100644 index 000000000..0068e9291 --- /dev/null +++ b/libraries/libapparmor/testsuite/test_multi/file_perm_network_receive_lp1582374.out @@ -0,0 +1,19 @@ +START +File: file_perm_network_receive_lp1582374.in +Event type: AA_RECORD_ALLOWED +Audit ID: 1462045985.636:2154 +Operation: file_perm +Mask: receive +Denied Mask: receive +Profile: /usr/local/apache-tomcat-8.0.33/bin/catalina.sh///usr/local/jdk1.8.0_92/bin/java +Command: java +PID: 12529 +Network family: inet6 +Socket type: stream +Protocol: tcp +Local addr: ::ffff:127.0.0.1 +Foreign addr: ::ffff:127.0.0.1 +Local port: 8080 +Foreign port: 52308 +Epoch: 1462045985 +Audit subid: 2154 diff --git a/libraries/libapparmor/testsuite/test_multi/file_perm_network_receive_lp1582374.profile b/libraries/libapparmor/testsuite/test_multi/file_perm_network_receive_lp1582374.profile new file mode 100644 index 000000000..4fac23a51 --- /dev/null +++ b/libraries/libapparmor/testsuite/test_multi/file_perm_network_receive_lp1582374.profile @@ -0,0 +1,7 @@ +/usr/local/apache-tomcat-8.0.33/bin/catalina.sh { + + ^/usr/local/jdk1.8.0_92/bin/java { + network inet6 stream, + + } +} diff --git a/utils/apparmor/logparser.py b/utils/apparmor/logparser.py index bcfff3c67..b2121f145 100644 --- a/utils/apparmor/logparser.py +++ b/utils/apparmor/logparser.py @@ -1,6 +1,6 @@ # ---------------------------------------------------------------------- # Copyright (C) 2013 Kshitij Gupta -# Copyright (C) 2015 Christian Boltz +# Copyright (C) 2015-2016 Christian Boltz # # This program is free software; you can redistribute it and/or # modify it under the terms of version 2 of the GNU General Public @@ -43,25 +43,6 @@ class ReadLog: # used to pre-filter log lines so that we hand over only relevant lines to LibAppArmor parsing RE_LOG_ALL = re.compile('(' + '|'.join(RE_log_parts) + ')') - - # Used by netdomain to identify the operation types - # New socket names - OPERATION_TYPES = {'create': 'net', - 'post_create': 'net', - 'bind': 'net', - 'connect': 'net', - 'listen': 'net', - 'accept': 'net', - 'sendmsg': 'net', - 'recvmsg': 'net', - 'getsockname': 'net', - 'getpeername': 'net', - 'getsockopt': 'net', - 'setsockopt': 'net', - 'socket_create': 'net', - 'sock_shutdown': 'net' - } - def __init__(self, pid, filename, existing_profiles, profile_dir, log): self.filename = filename self.profile_dir = profile_dir @@ -289,25 +270,7 @@ class ReadLog: else: self.debug_logger.debug('parse_event_for_tree: dropped exec event in %s' % e['profile']) - elif ( e['operation'].startswith('file_') or e['operation'].startswith('inode_') or - e['operation'] in ['open', 'truncate', 'mkdir', 'mknod', 'chmod', 'chown', 'rename_src', - 'rename_dest', 'unlink', 'rmdir', 'symlink_create', 'link', - 'sysctl', 'getattr', 'setattr', 'xattr'] ): - - # for some kernel-side reason, we get file-related log events without request_mask, see - # https://bugs.launchpad.net/apparmor/+bug/1466812/, https://bugs.launchpad.net/apparmor/+bug/1509030 and https://bugs.launchpad.net/apparmor/+bug/1540562 - # request_mask can also be '', see https://bugs.launchpad.net/ubuntu/+source/apparmor/+bug/1525119 - if not e['request_mask']: - self.debug_logger.debug('UNHANDLED (missing request_mask): %s' % e) - return None - - # sometimes network events come with an e['operation'] that matches the list of file operations - # see https://bugs.launchpad.net/apparmor/+bug/1577051 and https://bugs.launchpad.net/apparmor/+bug/1582374 - # XXX these events are network events, so we should map them as such - if 'send' in e['request_mask'] or 'receive' in e['request_mask']: - self.debug_logger.debug('UNHANDLED (request_mask is send or receive): %s' % e) - return None - + elif self.op_type(e) == 'file': # Map c (create) and d (delete) to w (logging is more detailed than the profile language) rmask = e['request_mask'] rmask = rmask.replace('c', 'w') @@ -366,7 +329,7 @@ class ReadLog: # self.log += [arrayref] # self.pid[child] = arrayref - elif self.op_type(e['operation']) == 'net': + elif self.op_type(e) == 'net': return(e['pid'], e['parent'], 'netdomain', [profile, hat, prog, aamode, e['family'], e['sock_type'], e['protocol']]) elif e['operation'] == 'change_hat': @@ -426,10 +389,57 @@ class ReadLog: self.logmark = '' return self.log - def op_type(self, operation): + # operation types that can be network or file operations + # (used by op_type() which checks some event details to decide) + OP_TYPE_FILE_OR_NET = { + # Note: op_type() also uses some startswith() checks which are not listed here! + 'create', + 'post_create', + 'bind', + 'connect', + 'listen', + 'accept', + 'sendmsg', + 'recvmsg', + 'getsockname', + 'getpeername', + 'getsockopt', + 'setsockopt', + 'socket_create', + 'sock_shutdown', + 'open', + 'truncate', + 'mkdir', + 'mknod', + 'chmod', + 'chown', + 'rename_src', + 'rename_dest', + 'unlink', + 'rmdir', + 'symlink_create', + 'link', + 'sysctl', + 'getattr', + 'setattr', + 'xattr', + } + + def op_type(self, event): """Returns the operation type if known, unkown otherwise""" - operation_type = self.OPERATION_TYPES.get(operation, 'unknown') - return operation_type + + if ( event['operation'].startswith('file_') or event['operation'].startswith('inode_') or event['operation'] in self.OP_TYPE_FILE_OR_NET ): + # file or network event? + if event['family'] and event['protocol'] and event['sock_type']: + # 'unix' events also use keywords like 'connect', but protocol is 0 and should therefore be filtered out + return 'net' + elif event['denied_mask']: + return 'file' + else: + raise AppArmorException('unknown file or network event type') + + else: + return 'unknown' def profile_exists(self, program): """Returns True if profile exists, False otherwise"""