[apparmor] [patch] logparser.py: improve file vs. network event recognition

Christian Boltz apparmor at cboltz.de
Sun Nov 20 15:52:46 UTC 2016


Hello,

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

(that will make quite some --fixes for bzr commit ;-)


I propose this patch for trunk and 2.10.


[ 02-logparser-improve-file-vs-net.diff ]

--- utils/apparmor/logparser.py	2016-11-20 16:00:37.374243431 +0100
+++ utils/apparmor/logparser.py	2016-11-20 16:01:19.158060468 +0100
@@ -1,6 +1,6 @@
 # ----------------------------------------------------------------------
 #    Copyright (C) 2013 Kshitij Gupta <kgupta8592 at gmail.com>
-#    Copyright (C) 2015 Christian Boltz <apparmor at cboltz.de>
+#    Copyright (C) 2015-2016 Christian Boltz <apparmor at cboltz.de>
 #
 #    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 @@
     # 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
@@ -295,25 +276,7 @@
             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')
@@ -373,7 +336,7 @@
 #                 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':
@@ -433,10 +396,57 @@
         self.logmark = ''
         return self.log
 
+    # 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, operation):
+    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"""

=== added file 'libraries/libapparmor/testsuite/test_multi/file_inherit_network_lp1509030.err'
=== added file 'libraries/libapparmor/testsuite/test_multi/file_inherit_network_lp1509030.in'
--- libraries/libapparmor/testsuite/test_multi/file_inherit_network_lp1509030.in	1970-01-01 00:00:00 +0000
+++ libraries/libapparmor/testsuite/test_multi/file_inherit_network_lp1509030.in	2016-11-20 15:28:09 +0000
@@ -0,0 +1,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

=== added file 'libraries/libapparmor/testsuite/test_multi/file_inherit_network_lp1509030.out'
--- libraries/libapparmor/testsuite/test_multi/file_inherit_network_lp1509030.out	1970-01-01 00:00:00 +0000
+++ libraries/libapparmor/testsuite/test_multi/file_inherit_network_lp1509030.out	2016-11-20 15:28:44 +0000
@@ -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

=== added file 'libraries/libapparmor/testsuite/test_multi/file_inherit_network_lp1509030.profile'
--- libraries/libapparmor/testsuite/test_multi/file_inherit_network_lp1509030.profile	1970-01-01 00:00:00 +0000
+++ libraries/libapparmor/testsuite/test_multi/file_inherit_network_lp1509030.profile	2016-11-20 14:47:46 +0000
@@ -0,0 +1,4 @@
+/usr/lib/NetworkManager/nm-dhcp-client.action {
+  network inet6 dgram,
+
+}

=== added file 'libraries/libapparmor/testsuite/test_multi/file_perm_network_lp1466812.err'
=== added file 'libraries/libapparmor/testsuite/test_multi/file_perm_network_lp1466812.in'
--- libraries/libapparmor/testsuite/test_multi/file_perm_network_lp1466812.in	1970-01-01 00:00:00 +0000
+++ libraries/libapparmor/testsuite/test_multi/file_perm_network_lp1466812.in	2015-10-28 20:34:22 +0000
@@ -0,0 +1,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

=== added file 'libraries/libapparmor/testsuite/test_multi/file_perm_network_lp1466812.out'
--- libraries/libapparmor/testsuite/test_multi/file_perm_network_lp1466812.out	1970-01-01 00:00:00 +0000
+++ libraries/libapparmor/testsuite/test_multi/file_perm_network_lp1466812.out	2016-11-20 15:32:21 +0000
@@ -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

=== added file 'libraries/libapparmor/testsuite/test_multi/file_perm_network_lp1466812.profile'
--- libraries/libapparmor/testsuite/test_multi/file_perm_network_lp1466812.profile	1970-01-01 00:00:00 +0000
+++ libraries/libapparmor/testsuite/test_multi/file_perm_network_lp1466812.profile	2016-11-18 21:10:38 +0000
@@ -0,0 +1,4 @@
+/usr/sbin/apache2 {
+  network inet6 stream,
+
+}

=== added file 'libraries/libapparmor/testsuite/test_multi/file_perm_network_receive_lp1577051.err'
=== added file 'libraries/libapparmor/testsuite/test_multi/file_perm_network_receive_lp1577051.in'
--- libraries/libapparmor/testsuite/test_multi/file_perm_network_receive_lp1577051.in	1970-01-01 00:00:00 +0000
+++ libraries/libapparmor/testsuite/test_multi/file_perm_network_receive_lp1577051.in	2016-11-20 14:37:50 +0000
@@ -0,0 +1,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"

=== added file 'libraries/libapparmor/testsuite/test_multi/file_perm_network_receive_lp1577051.out'
--- libraries/libapparmor/testsuite/test_multi/file_perm_network_receive_lp1577051.out	1970-01-01 00:00:00 +0000
+++ libraries/libapparmor/testsuite/test_multi/file_perm_network_receive_lp1577051.out	2016-11-20 15:32:08 +0000
@@ -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

=== added file 'libraries/libapparmor/testsuite/test_multi/file_perm_network_receive_lp1577051.profile'
--- libraries/libapparmor/testsuite/test_multi/file_perm_network_receive_lp1577051.profile	1970-01-01 00:00:00 +0000
+++ libraries/libapparmor/testsuite/test_multi/file_perm_network_receive_lp1577051.profile	2016-11-20 14:38:05 +0000
@@ -0,0 +1,7 @@
+/usr/sbin/apache2 {
+
+  ^www.xxxxxxxxxx.co.uk {
+    network inet6 stream,
+
+  }
+}

=== added file 'libraries/libapparmor/testsuite/test_multi/file_perm_network_receive_lp1582374.err'
=== added file 'libraries/libapparmor/testsuite/test_multi/file_perm_network_receive_lp1582374.in'
--- libraries/libapparmor/testsuite/test_multi/file_perm_network_receive_lp1582374.in	1970-01-01 00:00:00 +0000
+++ libraries/libapparmor/testsuite/test_multi/file_perm_network_receive_lp1582374.in	2016-05-20 22:34:29 +0000
@@ -0,0 +1,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"

=== added file 'libraries/libapparmor/testsuite/test_multi/file_perm_network_receive_lp1582374.out'
--- libraries/libapparmor/testsuite/test_multi/file_perm_network_receive_lp1582374.out	1970-01-01 00:00:00 +0000
+++ libraries/libapparmor/testsuite/test_multi/file_perm_network_receive_lp1582374.out	2016-11-20 15:31:55 +0000
@@ -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

=== added file 'libraries/libapparmor/testsuite/test_multi/file_perm_network_receive_lp1582374.profile'
--- libraries/libapparmor/testsuite/test_multi/file_perm_network_receive_lp1582374.profile	1970-01-01 00:00:00 +0000
+++ libraries/libapparmor/testsuite/test_multi/file_perm_network_receive_lp1582374.profile	2016-11-18 21:12:57 +0000
@@ -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,
+
+  }
+}




Regards,

Christian Boltz
-- 
Wenn man keine Vögel mag, ist es völlig in Ordnung, mit Kanonen auf
Spatzen zu schiessen.                         [Ratti in suse-linux]
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 801 bytes
Desc: This is a digitally signed message part.
URL: <https://lists.ubuntu.com/archives/apparmor/attachments/20161120/f9a50b48/attachment-0001.pgp>


More information about the AppArmor mailing list