2015-01-18 14:55:15 +01:00
# ----------------------------------------------------------------------
# Copyright (C) 2013 Kshitij Gupta <kgupta8592@gmail.com>
# Copyright (C) 2015 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
# License as published by the Free Software Foundation.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# ----------------------------------------------------------------------
import unittest
2022-08-07 20:32:07 -04:00
from apparmor . common import AppArmorException
2015-01-18 14:55:15 +01:00
from apparmor . logparser import ReadLog
2022-08-07 12:26:24 -04:00
from common_test import AATest , setup_all_loops # , setup_aa
2019-05-02 01:07:25 +02:00
2022-08-07 12:26:24 -04:00
2019-05-02 01:07:25 +02:00
class TestParseEvent ( AATest ) :
2022-06-18 14:30:49 -04:00
tests = ( )
2019-05-02 01:07:25 +02:00
2015-01-18 14:55:15 +01:00
def setUp ( self ) :
2019-05-04 00:22:46 +02:00
self . parser = ReadLog ( ' ' , ' ' , ' ' )
2015-01-18 14:55:15 +01:00
def test_parse_event_audit_1 ( self ) :
event = ' type=AVC msg=audit(1345027352.096:499): apparmor= " ALLOWED " operation= " rename_dest " parent=6974 profile= " /usr/sbin/httpd2-prefork//vhost_foo " name=2F686F6D652F7777772F666F6F2E6261722E696E2F68747470646F63732F61707061726D6F722F696D616765732F746573742F696D61676520312E6A7067 pid=20143 comm= " httpd2-prefork " requested_mask= " wc " denied_mask= " wc " fsuid=30 ouid=30 '
parsed_event = self . parser . parse_event ( event )
self . assertEqual ( parsed_event [ ' name ' ] , ' /home/www/foo.bar.in/httpdocs/apparmor/images/test/image 1.jpg ' )
self . assertEqual ( parsed_event [ ' profile ' ] , ' /usr/sbin/httpd2-prefork//vhost_foo ' )
self . assertEqual ( parsed_event [ ' aamode ' ] , ' PERMITTING ' )
2015-04-16 01:50:35 +02:00
self . assertEqual ( parsed_event [ ' request_mask ' ] , ' wc ' )
2015-01-18 14:55:15 +01:00
2015-10-03 20:18:54 +02:00
self . assertIsNotNone ( ReadLog . RE_LOG_ALL . search ( event ) )
2015-01-18 14:55:15 +01:00
def test_parse_event_audit_2 ( self ) :
event = ' type=AVC msg=audit(1322614918.292:4376): apparmor= " ALLOWED " operation= " file_perm " parent=16001 profile=666F6F20626172 name= " /home/foo/.bash_history " pid=17011 comm= " bash " requested_mask= " rw " denied_mask= " rw " fsuid=0 ouid=1000 '
parsed_event = self . parser . parse_event ( event )
self . assertEqual ( parsed_event [ ' name ' ] , ' /home/foo/.bash_history ' )
self . assertEqual ( parsed_event [ ' profile ' ] , ' foo bar ' )
self . assertEqual ( parsed_event [ ' aamode ' ] , ' PERMITTING ' )
2015-04-16 01:50:35 +02:00
self . assertEqual ( parsed_event [ ' request_mask ' ] , ' rw ' )
2015-01-18 14:55:15 +01:00
2015-10-03 20:18:54 +02:00
self . assertIsNotNone ( ReadLog . RE_LOG_ALL . search ( event ) )
2015-01-18 14:55:15 +01:00
def test_parse_event_syslog_1 ( self ) :
# from https://bugs.launchpad.net/apparmor/+bug/1399027
event = ' 2014-06-09T20:37:28.975070+02:00 geeko kernel: [21028.143765] type=1400 audit(1402339048.973:1421): apparmor= " ALLOWED " operation= " open " profile= " /home/cb/linuxtag/apparmor/scripts/hello " name= " /dev/tty " pid=14335 comm= " hello " requested_mask= " rw " denied_mask= " rw " fsuid=1000 ouid=0 '
parsed_event = self . parser . parse_event ( event )
self . assertEqual ( parsed_event [ ' name ' ] , ' /dev/tty ' )
self . assertEqual ( parsed_event [ ' profile ' ] , ' /home/cb/linuxtag/apparmor/scripts/hello ' )
self . assertEqual ( parsed_event [ ' aamode ' ] , ' PERMITTING ' )
2015-04-16 01:50:35 +02:00
self . assertEqual ( parsed_event [ ' request_mask ' ] , ' rw ' )
2015-01-18 14:55:15 +01:00
2015-10-03 20:18:54 +02:00
self . assertIsNotNone ( ReadLog . RE_LOG_ALL . search ( event ) )
2015-01-18 14:55:15 +01:00
def test_parse_event_syslog_2 ( self ) :
# from https://bugs.launchpad.net/apparmor/+bug/1399027
event = ' Dec 7 13:18:59 rosa kernel: audit: type=1400 audit(1417954745.397:82): apparmor= " ALLOWED " operation= " open " profile= " /home/simi/bin/aa-test " name= " /usr/bin/ " pid=3231 comm= " ls " requested_mask= " r " denied_mask= " r " fsuid=1000 ouid=0 '
parsed_event = self . parser . parse_event ( event )
self . assertEqual ( parsed_event [ ' name ' ] , ' /usr/bin/ ' )
self . assertEqual ( parsed_event [ ' profile ' ] , ' /home/simi/bin/aa-test ' )
self . assertEqual ( parsed_event [ ' aamode ' ] , ' PERMITTING ' )
2015-04-16 01:50:35 +02:00
self . assertEqual ( parsed_event [ ' request_mask ' ] , ' r ' )
2015-01-18 14:55:15 +01:00
2015-10-03 20:18:54 +02:00
self . assertIsNotNone ( ReadLog . RE_LOG_ALL . search ( event ) )
2015-01-18 14:55:15 +01:00
2015-03-03 22:17:05 +01:00
def test_parse_disconnected_path ( self ) :
# from https://bugzilla.opensuse.org/show_bug.cgi?id=918787
event = ' type=AVC msg=audit(1424425690.883:716630): apparmor= " ALLOWED " operation= " file_mmap " info= " Failed name lookup - disconnected path " error=-13 profile= " /sbin/klogd " name= " var/run/nscd/passwd " pid=25333 comm= " id " requested_mask= " r " denied_mask= " r " fsuid=1002 ouid=0 '
parsed_event = self . parser . parse_event ( event )
self . assertEqual ( parsed_event , {
' aamode ' : ' ERROR ' , # aamode for disconnected paths overridden aamode in parse_event()
' active_hat ' : None ,
' attr ' : None ,
2015-04-16 01:50:35 +02:00
' denied_mask ' : ' r ' ,
2015-03-03 22:17:05 +01:00
' error_code ' : 13 ,
2017-12-13 20:16:29 +01:00
' fsuid ' : 1002 ,
2015-03-03 22:17:05 +01:00
' info ' : ' Failed name lookup - disconnected path ' ,
' magic_token ' : 0 ,
' name ' : ' var/run/nscd/passwd ' ,
' name2 ' : None ,
' operation ' : ' file_mmap ' ,
2017-12-13 20:16:29 +01:00
' ouid ' : 0 ,
2015-03-03 22:17:05 +01:00
' parent ' : 0 ,
' pid ' : 25333 ,
' profile ' : ' /sbin/klogd ' ,
2015-04-16 01:50:35 +02:00
' request_mask ' : ' r ' ,
2015-03-03 22:17:05 +01:00
' resource ' : ' Failed name lookup - disconnected path ' ,
' task ' : 0 ,
2016-11-19 10:55:03 +01:00
' time ' : 1424425690 ,
' family ' : None ,
' protocol ' : None ,
' sock_type ' : None ,
2022-04-06 17:09:01 +00:00
' class ' : None ,
2015-03-03 22:17:05 +01:00
} )
2015-10-03 20:18:54 +02:00
self . assertIsNotNone ( ReadLog . RE_LOG_ALL . search ( event ) )
2015-03-03 22:17:05 +01:00
2024-07-23 16:09:53 +00:00
def test_get_rule_type ( self ) :
rules = [
( ' mount fstype=bpf options=(rw) random_label -> /sys/fs/bpf/, ' , ' mount ' ) ,
( ' unix send addr=@foo { a,b} peer=(label=splat), ' , ' unix ' ) ,
( ' userns create, # cmt ' , ' userns ' ) ,
( ' allow /tmp/foo ra, ' , ' file ' ) ,
( ' file rwix /foo, ' , ' file ' ) ,
( ' signal set=quit peer=unconfined, ' , ' signal ' )
]
for r , exp in rules :
self . assertEqual ( self . parser . get_rule_type ( r ) [ 0 ] , exp )
self . assertEqual ( self . parser . get_rule_type ( ' invalid rule, ' ) , None )
2024-08-13 10:49:11 +02:00
def test_create_rule_from_ev ( self ) :
events = [
( ' Sep 9 12:51:50 ubuntu-desktop kernel: [ 1612.746129] type=1400 audit(1284061910.975:672): apparmor= " DENIED " operation= " capable " parent=2663 profile= " /home/ubuntu/bzr/apparmor/tests/regression/apparmor/syscall_setpriority " pid=7292 comm= " syscall_setprio " capability=23 capname= " sys_nice " ' , ' capability ' , ' capability sys_nice, ' ) ,
( ' [ 1612.746129] audit: type=1400 audit(1284061910.975:672): apparmor= " DENIED " operation= " capable " parent=2663 profile= " /home/ubuntu/bzr/apparmor/tests/regression/apparmor/syscall_setpriority " pid=7292 comm= " syscall_setprio " capability=23 capname= " sys_nice " ' , ' capability ' , ' capability sys_nice, ' ) ,
( ' Sep 9 12:51:36 ubuntu-desktop kernel: [ 97.492562] audit: type=1400 audit(1431116353.523:77): apparmor= " DENIED " operation= " change_profile " profile= " /tests/regression/apparmor/changeprofile " pid=3459 comm= " changeprofile " target= " /tests/regression/apparmor/rename " ' , ' change_profile ' , ' change_profile -> /tests/regression/apparmor/rename, ' ) ,
( ' Jul 31 17:10:35 dbusdev-saucy-amd64 dbus[1692]: apparmor= " DENIED " operation= " dbus_method_call " bus= " session " name= " org.freedesktop.DBus " path= " /org/freedesktop/DBus " interface= " org.freedesktop.DBus " member= " Hello " mask= " send " pid=2922 profile= " /tmp/apparmor-2.8.0/tests/regression/apparmor/dbus_service " peer_profile= " unconfined " ' , ' dbus ' , ' dbus send bus=session path=/org/freedesktop/DBus interface=org.freedesktop.DBus member=Hello peer=(label=unconfined), ' ) ,
( ' Jul 31 17:11:16 dbusdev-saucy-amd64 dbus[1692]: apparmor= " DENIED " operation= " dbus_bind " bus= " session " name= " com.apparmor.Test " mask= " bind " pid=2940 profile= " /tmp/apparmor-2.8.0/tests/regression/apparmor/dbus_service " ' , ' dbus ' , ' dbus bind bus=session name=com.apparmor.Test, ' ) ,
( ' type=AVC msg=audit(1345027352.096:499): apparmor= " ALLOWED " operation= " rename_dest " parent=6974 profile= " /usr/sbin/httpd2-prefork//vhost_foo " name=2F686F6D652F7777772F666F6F2E6261722E696E2F68747470646F63732F61707061726D6F722F696D616765732F746573742F696D61676520312E6A7067 pid=20143 comm= " httpd2-prefork " requested_mask= " wc " denied_mask= " wc " fsuid=30 ouid=30 ' ,
' file ' , ' owner " /home/www/foo.bar.in/httpdocs/apparmor/images/test/image 1.jpg " w, ' ) , # noqa: E127
( ' 2014-06-09T20:37:28.975070+02:00 geeko kernel: [21028.143765] type=1400 audit(1402339048.973:1421): apparmor= " ALLOWED " operation= " open " profile= " /home/cb/linuxtag/apparmor/scripts/hello " name= " /dev/tty " pid=14335 comm= " hello " requested_mask= " rw " denied_mask= " rw " fsuid=1000 ouid=0 ' , ' file ' , ' /dev/tty rw, ' ) ,
( ' [ 4584.703379] audit: type=1400 audit(1680266735.359:69): apparmor= " DENIED " operation= " uring_sqpoll " class= " io_uring " profile= " /root/apparmor/tests/regression/apparmor/io_uring " pid=1320 comm= " io_uring " requested= " sqpoll " denied= " sqpoll " ' , ' io_uring ' , ' io_uring sqpoll, ' ) ,
( ' [ 4584.491076] audit: type=1400 audit(1680266735.147:63): apparmor= " DENIED " operation= " uring_override " class= " io_uring " profile= " /root/apparmor/tests/regression/apparmor/io_uring " pid=1193 comm= " io_uring " requested= " override_creds " denied= " override_creds " tcontext= " /root/apparmor/tests/regression/apparmor/io_uring " ' , ' io_uring ' , ' io_uring override_creds label=/root/apparmor/tests/regression/apparmor/io_uring, ' ) ,
( ' type=AVC msg=audit(1409700640.016:547457): apparmor= " DENIED " operation= " mount " info= " failed mntpnt match " error=-13 profile= " /home/ubuntu/bzr/apparmor/tests/regression/apparmor/mount " name= " /tmp/sdtest.19033-29001-MPfz98/mountpoint/ " pid=19085 comm= " mount " fstype= " ext2 " srcname= " /dev/loop0/ " flags= " rw, mand " ' , ' mount ' , ' mount fstype=(ext2) options=(mand, rw) /dev/loop0/ -> /tmp/sdtest.19033-29001-MPfz98/mountpoint/, ' ) ,
( ' type=AVC msg=audit(1709108389.303:12383): apparmor= " DENIED " operation= " mount " class= " mount " info= " failed mntpnt match " error=-13 profile= " /home/user/test/testmount " name= " /tmp/foo/ " pid=14155 comm= " testmount " flags= " ro, remount " ' , ' mount ' , ' mount options=(remount, ro) -> /tmp/foo/, ' ) ,
( ' type=AVC msg=audit(1709025786.045:43147): apparmor= " DENIED " operation= " umount " class= " mount " profile= " /home/user/test/testmount " name= " /mnt/a/ " pid=26697 comm= " testmount " ' , ' mount ' , ' umount /mnt/a/, ' ) ,
( ' Apr 05 19:36:19 ubuntu kernel: audit: type=1400 audit(1649187379.660:255): apparmor= " DENIED " operation= " create " profile= " /root/apparmor/tests/regression/apparmor/posix_mq_rcv " name= " /queuename " pid=791 comm= " posix_mq_rcv " requested= " create " denied= " create " class= " posix_mqueue " fsuid=0 ouid=0 ' , ' mqueue ' , ' mqueue create type=posix /queuename, ' ) ,
( ' Apr 05 19:36:29 ubuntu kernel: audit: type=1400 audit(1649187389.828:262): apparmor= " DENIED " operation= " open " profile= " /root/apparmor/tests/regression/apparmor/posix_mq_rcv " name= " /queuename " pid=848 comm= " posix_mq_rcv " requested= " read create " denied= " read " class= " posix_mqueue " fsuid=0 ouid=0 ' , ' mqueue ' , ' mqueue read type=posix /queuename, ' ) ,
( ' Apr 5 19:30:56 precise-amd64 kernel: [153073.826757] type=1400 audit(1308766940.698:3704): apparmor= " DENIED " operation= " sendmsg " parent=24737 profile= " /usr/bin/evince-thumbnailer " pid=24743 comm= " evince-thumbnai " laddr=192.168.66.150 lport=765 faddr=192.168.66.200 fport=2049 family= " inet " sock_type= " stream " protocol=6 ' , ' network ' , ' network inet stream ip=192.168.66.150 port=765 peer=(ip=192.168.66.200 port=2049), ' ) ,
( ' Apr 5 19:31:04 precise-amd64 kernel: [153073.826757] type=1400 audit(1308766940.698:3704): apparmor= " DENIED " operation= " sendmsg " parent=24737 profile= " /usr/bin/evince-thumbnailer " pid=24743 comm= " evince-thumbnai " lport=765 fport=2049 family= " inet " sock_type= " stream " protocol=6 ' , ' network ' , ' network inet stream port=765 peer=(port=2049), ' ) ,
( ' type=AVC msg=audit(1409700678.384:547594): apparmor= " DENIED " operation= " pivotroot " profile= " /home/ubuntu/bzr/apparmor/tests/regression/apparmor/pivot_root " name= " /tmp/sdtest.21082-7446-EeefO6/new_root/ " pid=21162 comm= " pivot_root " srcname= " /tmp/sdtest.21082-7446-EeefO6/new_root/put_old/ " ' , ' pivot_root ' , ' pivot_root oldroot=/tmp/sdtest.21082-7446-EeefO6/new_root/put_old/ /tmp/sdtest.21082-7446-EeefO6/new_root/, ' ) ,
( ' type=AVC msg=audit(1409700683.304:547661): apparmor= " DENIED " operation= " ptrace " profile= " /home/ubuntu/bzr/apparmor/tests/regression/apparmor/ptrace " pid=22465 comm= " ptrace " requested_mask= " tracedby " denied_mask= " tracedby " peer= " /home/ubuntu/bzr/apparmor/tests/regression/apparmor/ptrace " ' , ' ptrace ' , ' ptrace tracedby peer=/home/ubuntu/bzr/apparmor/tests/regression/apparmor/ptrace, ' ) ,
( ' 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 " ' , ' signal ' , ' signal send set=term peer=/usr/bin/pulseaudio///usr/lib/pulseaudio/pulse/gconf-helper, ' ) ,
( ' type=AVC msg=audit(1711454639.955:322): apparmor= " DENIED " operation= " connect " class= " net " profile= " /home/user/test/client.py " pid=80819 comm= " client.py " family= " unix " sock_type= " stream " protocol=0 requested= " send receive connect " denied= " send receive connect " addr=none peer_addr= " @test_abstract_socket " peer= " /home/user/test/server.py " ' , ' unix ' , ' unix (connect, receive, send) type=stream peer=(addr=@test_abstract_socket), ' ) ,
( ' type=AVC msg=audit(1711214183.107:298): apparmor= " DENIED " operation= " connect " class= " net " profile= " /home/user/test/client.py " pid=65262 comm= " server.py " family= " unix " sock_type= " stream " protocol=0 requested= " send receive accept " denied= " send accept " addr= " @test_abstract_socket " peer_addr=none peer= " unconfined " ' , ' unix ' , ' unix (accept, send) type=stream addr=@test_abstract_socket, ' ) ,
( ' [ 176.385388] audit: type=1400 audit(1666891380.570:78): apparmor= " DENIED " operation= " userns_create " class= " namespace " profile= " /usr/bin/userns_child_exec " pid=1785 comm= " userns_child_ex " requested= " userns_create " denied= " userns_create " ' , ' userns ' , ' userns create, ' ) ,
( ' [ 429.272003] audit: type=1400 audit(1720613712.153:168): apparmor= " AUDIT " operation= " userns_create " class= " namespace " info= " Userns create - transitioning profile " profile= " unconfined " pid=5630 comm= " unshare " requested= " userns_create " target= " unprivileged_userns " execpath= " /usr/bin/unshare " ' , ' userns ' , ' userns create, ' ) ,
]
for ev , expected_type , expected_rule in events :
parsed_event = self . parser . parse_event ( ev )
r = self . parser . create_rule_from_ev ( parsed_event )
self . assertIsNotNone ( r )
clean_rule = r . get_clean ( )
self . assertEqual ( self . parser . get_rule_type ( clean_rule ) [ 0 ] , expected_type )
self . assertEqual ( expected_rule , clean_rule )
2022-08-07 12:26:24 -04:00
2019-05-02 01:07:25 +02:00
class TestParseEventForTreeInvalid ( AATest ) :
2022-06-18 14:30:49 -04:00
tests = (
2022-08-07 12:26:24 -04:00
( ' type=AVC msg=audit(1556742870.707:3614): apparmor= " ALLOWED " operation= " open " profile= " /bin/hello " name= " /dev/tty " pid=12856 comm= " hello " requested_mask= " wr " denied_mask= " foo " fsuid=1000 ouid=0 ' , AppArmorException ) , # invalid file permissions "foo"
( ' type=AVC msg=audit(1556742870.707:3614): apparmor= " ALLOWED " operation= " open " profile= " /bin/hello " name= " /dev/tty " pid=12856 comm= " hello " requested_mask= " wr " denied_mask= " wr::w " fsuid=1000 ouid=0 ' , AppArmorException ) , # "wr::w" mixes owner and other
2022-06-18 14:30:49 -04:00
)
2019-05-02 01:07:25 +02:00
2024-08-13 10:49:11 +02:00
def setUp ( self ) :
self . parser = ReadLog ( ' ' , ' ' , ' ' )
2019-05-02 01:07:25 +02:00
def _fake_profile_exists ( self , program ) :
return True
2024-08-13 10:49:11 +02:00
def test_invalid_create_rule_from_ev ( self ) :
events = [
' Jul 31 17:11:16 dbusdev-saucy-amd64 dbus[1692]: apparmor= " DENIED " operation= " invalid " bus= " session " name= " com.apparmor.Test " mask= " bind " pid=2940 profile= " /tmp/apparmor-2.8.0/tests/regression/apparmor/dbus_service " ' , # operation is invalid
' type=AVC msg=audit(1709108389.303:12383): apparmor= " DENIED " operation= " mount " class= " mount " info= " failed mntpnt match " error=-13 profile= " /home/user/test/testmount " name= " /tmp/foo/ " pid=14155 comm= " testmount " flags= " invalid " ' , # invalid flag
' [ 176.385388] audit: type=1400 audit(1666891380.570:78): apparmor= " DENIED " operation= " userns_create " class= " namespace " profile= " /usr/bin/userns_child_exec " pid=1785 comm= " userns_child_ex " requested= " userns_create " denied= " invalid " ' # invalid denied
]
for ev in events :
parsed_event = self . parser . parse_event ( ev )
r = self . parser . create_rule_from_ev ( parsed_event )
self . assertEqual ( r , None )
2019-05-02 01:07:25 +02:00
def _run_test ( self , params , expected ) :
self . parser . profile_exists = self . _fake_profile_exists # inject fake function that always returns True - much easier than handing over a ProfileList object to __init__
parsed_event = self . parser . parse_event ( params )
with self . assertRaises ( expected ) :
self . parser . parse_event_for_tree ( parsed_event )
2015-01-18 14:55:15 +01:00
2022-08-07 12:26:24 -04:00
2019-05-02 01:07:25 +02:00
setup_all_loops ( __name__ )
2015-01-18 14:55:15 +01:00
if __name__ == " __main__ " :
2018-04-08 20:18:30 +02:00
unittest . main ( verbosity = 1 )