2
0
mirror of https://gitlab.com/apparmor/apparmor synced 2025-08-22 01:57:43 +00:00

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 <steve@nxnw.org> for trunk and 2.10.
This commit is contained in:
Christian Boltz 2016-12-06 22:24:56 +01:00
parent 8cc7b73552
commit 5c26296b9f
17 changed files with 148 additions and 43 deletions

View File

@ -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

View File

@ -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

View File

@ -0,0 +1,4 @@
/usr/lib/NetworkManager/nm-dhcp-client.action {
network inet6 dgram,
}

View File

@ -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

View File

@ -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

View File

@ -0,0 +1,4 @@
/usr/sbin/apache2 {
network inet6 stream,
}

View File

@ -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"

View File

@ -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

View File

@ -0,0 +1,7 @@
/usr/sbin/apache2 {
^www.xxxxxxxxxx.co.uk {
network inet6 stream,
}
}

View File

@ -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"

View File

@ -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

View File

@ -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,
}
}

View File

@ -1,6 +1,6 @@
# ----------------------------------------------------------------------
# Copyright (C) 2013 Kshitij Gupta <kgupta8592@gmail.com>
# Copyright (C) 2015 Christian Boltz <apparmor@cboltz.de>
# Copyright (C) 2015-2016 Christian Boltz <apparmor@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 @@ 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"""