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:
parent
8cc7b73552
commit
5c26296b9f
@ -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
|
@ -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
|
@ -0,0 +1,4 @@
|
||||
/usr/lib/NetworkManager/nm-dhcp-client.action {
|
||||
network inet6 dgram,
|
||||
|
||||
}
|
@ -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
|
@ -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
|
@ -0,0 +1,4 @@
|
||||
/usr/sbin/apache2 {
|
||||
network inet6 stream,
|
||||
|
||||
}
|
@ -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"
|
@ -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
|
@ -0,0 +1,7 @@
|
||||
/usr/sbin/apache2 {
|
||||
|
||||
^www.xxxxxxxxxx.co.uk {
|
||||
network inet6 stream,
|
||||
|
||||
}
|
||||
}
|
@ -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"
|
@ -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
|
@ -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,
|
||||
|
||||
}
|
||||
}
|
@ -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"""
|
||||
|
Loading…
x
Reference in New Issue
Block a user