2019-02-03 23:01:30 +01:00
#! /usr/bin/python3
# ------------------------------------------------------------------
#
# Copyright (C) 2011-2012 Canonical Ltd.
# Copyright (C) 2019 Otto Kekäläinen
#
# 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 published by the Free Software Foundation.
#
# ------------------------------------------------------------------
import os
2024-02-21 16:53:35 -03:00
import pwd
2019-02-03 23:01:30 +01:00
import signal
import subprocess
2025-01-22 12:04:35 -08:00
import sys
2019-02-03 23:01:30 +01:00
import time
2019-02-11 20:18:44 +02:00
import unittest
2022-07-17 21:13:19 -04:00
from tempfile import NamedTemporaryFile
2024-02-21 16:53:35 -03:00
from datetime import datetime
2019-02-11 20:18:44 +02:00
import apparmor . aa as aa
2022-08-07 20:32:07 -04:00
from common_test import AATest , setup_aa , setup_all_loops
2019-02-03 23:01:30 +01:00
# The location of the aa-notify utility can be overridden by setting
# the APPARMOR_NOTIFY environment variable; this is useful for running
# these tests in an installed environment
2020-10-25 16:46:07 +01:00
aanotify_bin = [ " ../aa-notify " ]
2019-02-03 23:01:30 +01:00
2022-08-07 12:26:24 -04:00
2019-02-03 23:01:30 +01:00
# http://www.chiark.greenend.org.uk/ucgi/~cjwatson/blosxom/2009-07-02-python-sigpipe.html
# This is needed so that the subprocesses that produce endless output
# actually quit when the reader goes away.
def subprocess_setup ( ) :
# Python installs a SIGPIPE handler by default. This is usually not what
# non-Python subprocesses expect.
signal . signal ( signal . SIGPIPE , signal . SIG_DFL )
def cmd ( command ) :
2022-08-07 14:57:30 -04:00
""" Try to execute given command (array) and return its stdout, or return
a textual error if it failed . """
2019-02-03 23:01:30 +01:00
try :
sp = subprocess . Popen (
command ,
stdin = None ,
stdout = subprocess . PIPE ,
stderr = subprocess . PIPE ,
close_fds = True ,
preexec_fn = subprocess_setup
)
except OSError as e :
2022-06-18 14:30:49 -04:00
return 127 , str ( e )
2019-02-03 23:01:30 +01:00
stdout , stderr = sp . communicate ( input )
# If there was some error output, show that instead of stdout to ensure
# test fails and does not mask potentially major warnings and errors.
if stderr :
out = stderr
else :
out = stdout
2022-06-18 14:30:49 -04:00
return sp . returncode , out . decode ( ' utf-8 ' )
2019-02-03 23:01:30 +01:00
2024-02-23 17:15:14 -03:00
class AANotifyBase ( AATest ) :
2019-02-03 23:01:30 +01:00
2024-02-23 17:15:14 -03:00
def create_logfile_contents ( _time ) :
2024-02-21 16:53:35 -03:00
""" Create temporary log file with 30 entries of different age """
2019-02-03 23:01:30 +01:00
test_logfile_contents_999_days_old = \
''' Feb 4 13:40:38 XPS-13-9370 kernel: [128552.834382] audit: type=1400 audit( {epoch} :113): apparmor= " ALLOWED " operation= " exec " profile= " libreoffice-soffice " name= " /bin/uname " pid=4097 comm= " sh " requested_mask= " x " denied_mask= " x " fsuid=1001 ouid=0 target= " libreoffice-soffice//null-/bin/uname "
Feb 4 13 : 40 : 38 XPS - 13 - 9370 kernel : [ 128552.834888 ] audit : type = 1400 audit ( { epoch } : 114 ) : apparmor = " ALLOWED " operation = " file_inherit " profile = " libreoffice-soffice//null-/bin/uname " name = " /dev/null " pid = 4097 comm = " uname " requested_mask = " w " denied_mask = " w " fsuid = 1001 ouid = 0
Feb 4 13 : 40 : 38 XPS - 13 - 9370 kernel : [ 128552.834890 ] audit : type = 1400 audit ( { epoch } : 115 ) : apparmor = " ALLOWED " operation = " file_mmap " profile = " libreoffice-soffice//null-/bin/uname " name = " /bin/uname " pid = 4097 comm = " uname " requested_mask = " rm " denied_mask = " rm " fsuid = 1001 ouid = 0
Feb 4 13 : 40 : 38 XPS - 13 - 9370 kernel : [ 128552.835136 ] audit : type = 1400 audit ( { epoch } : 116 ) : apparmor = " ALLOWED " operation = " file_mmap " profile = " libreoffice-soffice//null-/bin/uname " name = " /lib/x86_64-linux-gnu/ld-2.27.so " pid = 4097 comm = " uname " requested_mask = " rm " denied_mask = " rm " fsuid = 1001 ouid = 0
Feb 4 13 : 40 : 38 XPS - 13 - 9370 kernel : [ 128552.835377 ] audit : type = 1400 audit ( { epoch } : 117 ) : apparmor = " ALLOWED " operation = " open " profile = " libreoffice-soffice//null-/bin/uname " name = " /etc/ld.so.cache " pid = 4097 comm = " uname " requested_mask = " r " denied_mask = " r " fsuid = 1001 ouid = 0
Feb 4 13 : 40 : 38 XPS - 13 - 9370 kernel : [ 128552.835405 ] audit : type = 1400 audit ( { epoch } : 118 ) : apparmor = " ALLOWED " operation = " open " profile = " libreoffice-soffice//null-/bin/uname " name = " /lib/x86_64-linux-gnu/libc-2.27.so " pid = 4097 comm = " uname " requested_mask = " r " denied_mask = " r " fsuid = 1001 ouid = 0
Feb 4 13 : 40 : 38 XPS - 13 - 9370 kernel : [ 128552.835421 ] audit : type = 1400 audit ( { epoch } : 119 ) : apparmor = " ALLOWED " operation = " file_mmap " profile = " libreoffice-soffice//null-/bin/uname " name = " /lib/x86_64-linux-gnu/libc-2.27.so " pid = 4097 comm = " uname " requested_mask = " rm " denied_mask = " rm " fsuid = 1001 ouid = 0
Feb 4 13 : 40 : 38 XPS - 13 - 9370 kernel : [ 128552.835696 ] audit : type = 1400 audit ( { epoch } : 120 ) : apparmor = " ALLOWED " operation = " open " profile = " libreoffice-soffice//null-/bin/uname " name = " /usr/lib/locale/locale-archive " pid = 4097 comm = " uname " requested_mask = " r " denied_mask = " r " fsuid = 1001 ouid = 0
Feb 4 13 : 40 : 38 XPS - 13 - 9370 kernel : [ 128552.875891 ] audit : type = 1400 audit ( { epoch } : 121 ) : apparmor = " ALLOWED " operation = " exec " profile = " libreoffice-soffice " name = " /usr/bin/file " pid = 4111 comm = " soffice.bin " requested_mask = " x " denied_mask = " x " fsuid = 1001 ouid = 0 target = " libreoffice-soffice//null-/usr/bin/file "
Feb 4 13 : 40 : 38 XPS - 13 - 9370 kernel : [ 128552.880347 ] audit : type = 1400 audit ( { epoch } : 122 ) : apparmor = " ALLOWED " operation = " file_mmap " profile = " libreoffice-soffice//null-/usr/bin/file " name = " /usr/bin/file " pid = 4111 comm = " file " requested_mask = " rm " denied_mask = " rm " fsuid = 1001 ouid = 0
2024-05-17 13:53:42 +02:00
''' .format(epoch=round(_time, 3) - 60 * 60 * 24 * 999) # noqa: E128
2019-02-03 23:01:30 +01:00
test_logfile_contents_30_days_old = \
''' Feb 4 13:40:38 XPS-13-9370 kernel: [128552.834382] audit: type=1400 audit( {epoch} :113): apparmor= " ALLOWED " operation= " exec " profile= " libreoffice-soffice " name= " /bin/uname " pid=4097 comm= " sh " requested_mask= " x " denied_mask= " x " fsuid=1001 ouid=0 target= " libreoffice-soffice//null-/bin/uname "
Feb 4 13 : 40 : 38 XPS - 13 - 9370 kernel : [ 128552.834888 ] audit : type = 1400 audit ( { epoch } : 114 ) : apparmor = " ALLOWED " operation = " file_inherit " profile = " libreoffice-soffice//null-/bin/uname " name = " /dev/null " pid = 4097 comm = " uname " requested_mask = " w " denied_mask = " w " fsuid = 1001 ouid = 0
Feb 4 13 : 40 : 38 XPS - 13 - 9370 kernel : [ 128552.834890 ] audit : type = 1400 audit ( { epoch } : 115 ) : apparmor = " ALLOWED " operation = " file_mmap " profile = " libreoffice-soffice//null-/bin/uname " name = " /bin/uname " pid = 4097 comm = " uname " requested_mask = " rm " denied_mask = " rm " fsuid = 1001 ouid = 0
Feb 4 13 : 40 : 38 XPS - 13 - 9370 kernel : [ 128552.835136 ] audit : type = 1400 audit ( { epoch } : 116 ) : apparmor = " ALLOWED " operation = " file_mmap " profile = " libreoffice-soffice//null-/bin/uname " name = " /lib/x86_64-linux-gnu/ld-2.27.so " pid = 4097 comm = " uname " requested_mask = " rm " denied_mask = " rm " fsuid = 1001 ouid = 0
Feb 4 13 : 40 : 38 XPS - 13 - 9370 kernel : [ 128552.835377 ] audit : type = 1400 audit ( { epoch } : 117 ) : apparmor = " ALLOWED " operation = " open " profile = " libreoffice-soffice//null-/bin/uname " name = " /etc/ld.so.cache " pid = 4097 comm = " uname " requested_mask = " r " denied_mask = " r " fsuid = 1001 ouid = 0
Feb 4 13 : 40 : 38 XPS - 13 - 9370 kernel : [ 128552.835405 ] audit : type = 1400 audit ( { epoch } : 118 ) : apparmor = " ALLOWED " operation = " open " profile = " libreoffice-soffice//null-/bin/uname " name = " /lib/x86_64-linux-gnu/libc-2.27.so " pid = 4097 comm = " uname " requested_mask = " r " denied_mask = " r " fsuid = 1001 ouid = 0
Feb 4 13 : 40 : 38 XPS - 13 - 9370 kernel : [ 128552.835421 ] audit : type = 1400 audit ( { epoch } : 119 ) : apparmor = " ALLOWED " operation = " file_mmap " profile = " libreoffice-soffice//null-/bin/uname " name = " /lib/x86_64-linux-gnu/libc-2.27.so " pid = 4097 comm = " uname " requested_mask = " rm " denied_mask = " rm " fsuid = 1001 ouid = 0
Feb 4 13 : 40 : 38 XPS - 13 - 9370 kernel : [ 128552.835696 ] audit : type = 1400 audit ( { epoch } : 120 ) : apparmor = " ALLOWED " operation = " open " profile = " libreoffice-soffice//null-/bin/uname " name = " /usr/lib/locale/locale-archive " pid = 4097 comm = " uname " requested_mask = " r " denied_mask = " r " fsuid = 1001 ouid = 0
Feb 4 13 : 40 : 38 XPS - 13 - 9370 kernel : [ 128552.875891 ] audit : type = 1400 audit ( { epoch } : 121 ) : apparmor = " ALLOWED " operation = " exec " profile = " libreoffice-soffice " name = " /usr/bin/file " pid = 4111 comm = " soffice.bin " requested_mask = " x " denied_mask = " x " fsuid = 1001 ouid = 0 target = " libreoffice-soffice//null-/usr/bin/file "
Feb 4 13 : 40 : 38 XPS - 13 - 9370 kernel : [ 128552.880347 ] audit : type = 1400 audit ( { epoch } : 122 ) : apparmor = " ALLOWED " operation = " file_mmap " profile = " libreoffice-soffice//null-/usr/bin/file " name = " /usr/bin/file " pid = 4111 comm = " file " requested_mask = " rm " denied_mask = " rm " fsuid = 1001 ouid = 0
2024-05-17 13:53:42 +02:00
''' .format(epoch=round(_time, 3) - 60 * 60 * 24 * 30) # noqa: E128
2019-02-03 23:01:30 +01:00
test_logfile_contents_unrelevant_entries = \
''' Feb 1 19:35:44 XPS-13-9370 kernel: [99848.048761] audit: type=1400 audit(1549042544.968:72): apparmor= " STATUS " operation= " profile_load " profile= " unconfined " name= " /snap/core/6350/usr/lib/snapd/snap-confine " pid=12871 comm= " apparmor_parser "
Feb 2 00 : 40 : 09 XPS - 13 - 9370 kernel : [ 103014.549071 ] audit : type = 1400 audit ( 1549060809.600 : 89 ) : apparmor = " STATUS " operation = " profile_load " profile = " unconfined " name = " docker-default " pid = 17195 comm = " apparmor_parser "
Feb 4 20 : 05 : 42 XPS - 13 - 9370 kernel : [ 132557.202931 ] audit : type = 1400 audit ( 1549303542.661 : 136 ) : apparmor = " STATUS " operation = " profile_replace " info = " same as current profile, skipping " profile = " unconfined " name = " snap.atom.apm " pid = 11306 comm = " apparmor_parser "
2024-05-17 13:53:42 +02:00
''' # noqa: E128
2019-02-03 23:01:30 +01:00
test_logfile_contents_0_seconds_old = \
''' Feb 4 13:40:38 XPS-13-9370 kernel: [128552.834382] audit: type=1400 audit( {epoch} :113): apparmor= " ALLOWED " operation= " exec " profile= " libreoffice-soffice " name= " /bin/uname " pid=4097 comm= " sh " requested_mask= " x " denied_mask= " x " fsuid=1001 ouid=0 target= " libreoffice-soffice//null-/bin/uname "
Feb 4 13 : 40 : 38 XPS - 13 - 9370 kernel : [ 128552.834888 ] audit : type = 1400 audit ( { epoch } : 114 ) : apparmor = " ALLOWED " operation = " file_inherit " profile = " libreoffice-soffice//null-/bin/uname " name = " /dev/null " pid = 4097 comm = " uname " requested_mask = " w " denied_mask = " w " fsuid = 1001 ouid = 0
Feb 4 13 : 40 : 38 XPS - 13 - 9370 kernel : [ 128552.834890 ] audit : type = 1400 audit ( { epoch } : 115 ) : apparmor = " ALLOWED " operation = " file_mmap " profile = " libreoffice-soffice//null-/bin/uname " name = " /bin/uname " pid = 4097 comm = " uname " requested_mask = " rm " denied_mask = " rm " fsuid = 1001 ouid = 0
Feb 4 13 : 40 : 38 XPS - 13 - 9370 kernel : [ 128552.835136 ] audit : type = 1400 audit ( { epoch } : 116 ) : apparmor = " ALLOWED " operation = " file_mmap " profile = " libreoffice-soffice//null-/bin/uname " name = " /lib/x86_64-linux-gnu/ld-2.27.so " pid = 4097 comm = " uname " requested_mask = " rm " denied_mask = " rm " fsuid = 1001 ouid = 0
Feb 4 13 : 40 : 38 XPS - 13 - 9370 kernel : [ 128552.835377 ] audit : type = 1400 audit ( { epoch } : 117 ) : apparmor = " ALLOWED " operation = " open " profile = " libreoffice-soffice//null-/bin/uname " name = " /etc/ld.so.cache " pid = 4097 comm = " uname " requested_mask = " r " denied_mask = " r " fsuid = 1001 ouid = 0
Feb 4 13 : 40 : 38 XPS - 13 - 9370 kernel : [ 128552.835405 ] audit : type = 1400 audit ( { epoch } : 118 ) : apparmor = " ALLOWED " operation = " open " profile = " libreoffice-soffice//null-/bin/uname " name = " /lib/x86_64-linux-gnu/libc-2.27.so " pid = 4097 comm = " uname " requested_mask = " r " denied_mask = " r " fsuid = 1001 ouid = 0
Feb 4 13 : 40 : 38 XPS - 13 - 9370 kernel : [ 128552.835421 ] audit : type = 1400 audit ( { epoch } : 119 ) : apparmor = " ALLOWED " operation = " file_mmap " profile = " libreoffice-soffice//null-/bin/uname " name = " /lib/x86_64-linux-gnu/libc-2.27.so " pid = 4097 comm = " uname " requested_mask = " rm " denied_mask = " rm " fsuid = 1001 ouid = 0
Feb 4 13 : 40 : 38 XPS - 13 - 9370 kernel : [ 128552.835696 ] audit : type = 1400 audit ( { epoch } : 120 ) : apparmor = " ALLOWED " operation = " open " profile = " libreoffice-soffice//null-/bin/uname " name = " /usr/lib/locale/locale-archive " pid = 4097 comm = " uname " requested_mask = " r " denied_mask = " r " fsuid = 1001 ouid = 0
Feb 4 13 : 40 : 38 XPS - 13 - 9370 kernel : [ 128552.875891 ] audit : type = 1400 audit ( { epoch } : 121 ) : apparmor = " ALLOWED " operation = " exec " profile = " libreoffice-soffice " name = " /usr/bin/file " pid = 4111 comm = " soffice.bin " requested_mask = " x " denied_mask = " x " fsuid = 1001 ouid = 0 target = " libreoffice-soffice//null-/usr/bin/file "
Feb 4 13 : 40 : 38 XPS - 13 - 9370 kernel : [ 128552.880347 ] audit : type = 1400 audit ( { epoch } : 122 ) : apparmor = " ALLOWED " operation = " file_mmap " profile = " libreoffice-soffice//null-/usr/bin/file " name = " /usr/bin/file " pid = 4111 comm = " file " requested_mask = " rm " denied_mask = " rm " fsuid = 1001 ouid = 0
2024-05-17 13:53:42 +02:00
''' .format(epoch=round(_time, 3)) # noqa: E128
2024-02-21 16:53:35 -03:00
return test_logfile_contents_999_days_old \
+ test_logfile_contents_30_days_old \
+ test_logfile_contents_unrelevant_entries \
+ test_logfile_contents_0_seconds_old
2019-02-03 23:01:30 +01:00
2024-02-23 17:15:14 -03:00
@classmethod
def setUpClass ( cls ) :
2024-02-21 16:53:35 -03:00
file_current = NamedTemporaryFile ( " w+ " , prefix = ' test-aa-notify- ' , delete = False )
file_last_login = NamedTemporaryFile ( " w+ " , prefix = ' test-aa-notify- ' , delete = False )
2024-02-23 17:15:14 -03:00
cls . test_logfile_current = file_current . name
cls . test_logfile_last_login = file_last_login . name
2024-02-21 16:53:35 -03:00
2024-02-23 17:15:14 -03:00
current_time_contents = cls . create_logfile_contents ( time . time ( ) )
2024-02-21 16:53:35 -03:00
file_current . write ( current_time_contents )
if os . path . isfile ( ' /var/log/wtmp ' ) :
if os . name == " posix " :
username = pwd . getpwuid ( os . geteuid ( ) ) . pw_name
else :
username = os . environ . get ( ' USER ' )
if not username and hasattr ( os , ' getlogin ' ) :
username = os . getlogin ( )
if ' SUDO_USER ' in os . environ :
username = os . environ . get ( ' SUDO_USER ' )
2024-08-07 15:18:58 -07:00
return_code , output = cmd ( [ ' last ' , username , ' --fullnames ' , ' --time-format ' , ' iso ' ] )
2024-03-12 19:37:29 +01:00
output = output . split ( ' \n ' ) [ 0 ] # the first line is enough
2025-01-27 10:15:45 -08:00
# example of output (util-linux last command):
2024-02-21 16:53:35 -03:00
# ubuntu tty7 :0 2024-01-05T14:29:11-03:00 gone - no logout
2025-01-27 10:15:45 -08:00
# example of output (wtmpdb last command, local login):
# ubuntu tty7 2025-01-15T09:32:49-0800 - still logged in
# example of output (wtmpdb last command, remote login)
# ubuntu tty7 192.168.122.1 2024-01-05T14:29:11-03:00 gone - no logout
2024-02-21 16:53:35 -03:00
if output . startswith ( username ) :
2025-01-27 10:15:45 -08:00
# Check both possible columns for the date
try :
last_login = output . split ( ) [ 3 ]
last_login_epoch = datetime . fromisoformat ( last_login ) . timestamp ( )
except ( IndexError , ValueError ) :
last_login = output . split ( ) [ 2 ]
last_login_epoch = datetime . fromisoformat ( last_login ) . timestamp ( )
2024-02-21 16:53:35 -03:00
# add 60 seconds to the epoch so that the time in the logs are AFTER login time
2024-02-23 17:15:14 -03:00
last_login_contents = cls . create_logfile_contents ( last_login_epoch + 60 )
2024-02-21 16:53:35 -03:00
file_last_login . write ( last_login_contents )
2019-02-03 23:01:30 +01:00
2024-02-23 17:15:14 -03:00
@classmethod
def tearDownClass ( cls ) :
2022-08-07 14:57:30 -04:00
""" Remove temporary log file after tests ended """
2019-02-03 23:01:30 +01:00
2024-02-23 17:15:14 -03:00
if cls . test_logfile_current and os . path . exists ( cls . test_logfile_current ) :
os . remove ( cls . test_logfile_current )
if cls . test_logfile_last_login and os . path . exists ( cls . test_logfile_last_login ) :
os . remove ( cls . test_logfile_last_login )
class AANotifyTest ( AANotifyBase ) :
2019-02-03 23:01:30 +01:00
2019-01-09 23:59:40 +01:00
# The Perl aa-notify script was written so, that it will checked for kern.log
2019-02-09 13:24:53 +02:00
# before printing help when invoked without arguments (sic!).
@unittest.skipUnless ( os . path . isfile ( ' /var/log/kern.log ' ) , ' Requires kern.log on system ' )
2019-02-03 23:01:30 +01:00
def test_no_arguments ( self ) :
2022-08-07 14:57:30 -04:00
""" Test using no arguments at all """
2019-02-03 23:01:30 +01:00
2019-01-09 23:59:40 +01:00
expected_return_code = 0
expected_output_has = ' usage: aa-notify '
2019-02-03 23:01:30 +01:00
2020-10-25 16:46:07 +01:00
return_code , output = cmd ( aanotify_bin )
2023-02-19 16:26:14 -05:00
result = ' Got return code {} , expected {} \n ' . format ( return_code , expected_return_code )
2019-02-03 23:01:30 +01:00
self . assertEqual ( expected_return_code , return_code , result + output )
2023-02-19 16:26:14 -05:00
result = ' Got output " {} " , expected " {} " \n ' . format ( output , expected_output_has )
2019-02-03 23:01:30 +01:00
self . assertIn ( expected_output_has , output , result + output )
def test_help_contents ( self ) :
2022-08-07 14:57:30 -04:00
""" Test output of help text """
2019-02-03 23:01:30 +01:00
expected_return_code = 0
2022-02-14 19:59:21 +01:00
expected_output_1 = \
2019-01-09 23:59:40 +01:00
''' usage: aa-notify [-h] [-p] [--display DISPLAY] [-f FILE] [-l] [-s NUM] [-v]
2024-11-26 18:35:37 +00:00
[ - u USER ] [ - w NUM ] [ - m ] [ - - prompt - filter PF ] [ - - debug ]
2024-08-13 16:58:25 +00:00
[ - - filter . profile PROFILE ] [ - - filter . operation OPERATION ]
[ - - filter . name NAME ] [ - - filter . denied DENIED ]
[ - - filter . family FAMILY ] [ - - filter . socket SOCKET ]
2019-02-03 23:01:30 +01:00
Display AppArmor notifications or messages for DENIED entries .
2024-05-17 13:53:42 +02:00
''' # noqa: E128
2019-02-03 23:01:30 +01:00
2022-02-14 19:59:21 +01:00
expected_output_2 = \
'''
2019-01-09 23:59:40 +01:00
- h , - - help show this help message and exit
- p , - - poll poll AppArmor logs and display notifications
2019-04-19 23:12:32 +03:00
- - display DISPLAY set the DISPLAY environment variable ( might be needed if
sudo resets $ DISPLAY )
2025-01-21 20:52:36 +01:00
- f , - - file FILE search FILE for AppArmor messages
2019-01-09 23:59:40 +01:00
- l , - - since - last display stats since last login
2025-01-21 20:52:36 +01:00
- s , - - since - days NUM show stats for last NUM days ( can be used alone or with
2019-04-19 23:12:32 +03:00
- p )
2019-01-09 23:59:40 +01:00
- v , - - verbose show messages with stats
2025-01-21 20:52:36 +01:00
- u , - - user USER user to drop privileges to when not using sudo
- w , - - wait NUM wait NUM seconds before displaying notifications ( with
2019-01-09 23:59:40 +01:00
- p )
2024-11-26 18:35:37 +00:00
- m , - - merge - notifications
Merge notification for improved readability ( with - p )
2024-08-13 16:58:25 +00:00
- - prompt - filter PF kind of operations which display a popup prompt
2019-01-09 23:59:40 +01:00
- - debug debug mode
2024-02-23 17:15:14 -03:00
Filtering options :
Filters are used to reduce the output of information to only those entries
that will match the filter . Filters use Python ' s regular expression syntax.
- - filter . profile PROFILE
regular expression to match the profile
- - filter . operation OPERATION
regular expression to match the operation
- - filter . name NAME regular expression to match the name
- - filter . denied DENIED
regular expression to match the denied mask
- - filter . family FAMILY
regular expression to match the network family
- - filter . socket SOCKET
regular expression to match the network socket type
2024-05-17 13:53:42 +02:00
''' # noqa: E128
2019-02-03 23:01:30 +01:00
2025-01-21 20:52:36 +01:00
if sys . version_info [ : 2 ] < ( 3 , 13 ) :
# Python 3.13 tweaked argparse output [1]. When running on older
# Python versions, we adapt the expected output to match.
#
# https://github.com/python/cpython/pull/103372
patches = [ (
2025-01-28 20:12:25 +01:00
' , --file FILE ' ,
' FILE, --file FILE ' ,
2025-01-21 20:52:36 +01:00
) , (
2025-01-28 20:12:25 +01:00
' , --since-days NUM show stats for last NUM days (can be used alone or with ' ,
' NUM, --since-days NUM \n '
2025-01-21 20:52:36 +01:00
+ ' show stats for last NUM days (can be used alone or with ' ,
) , (
2025-01-28 20:12:25 +01:00
' , --user USER ' ,
' USER, --user USER ' ,
2025-01-21 20:52:36 +01:00
) , (
2025-01-28 20:12:25 +01:00
' , --wait NUM ' ,
' NUM, --wait NUM ' ,
2025-01-21 20:52:36 +01:00
) ]
for patch in patches :
expected_output_2 = expected_output_2 . replace ( patch [ 0 ] , patch [ 1 ] )
2020-10-25 16:46:07 +01:00
return_code , output = cmd ( aanotify_bin + [ ' --help ' ] )
2023-02-19 16:26:14 -05:00
result = ' Got return code {} , expected {} \n ' . format ( return_code , expected_return_code )
2019-02-03 23:01:30 +01:00
self . assertEqual ( expected_return_code , return_code , result + output )
2022-02-14 19:59:21 +01:00
self . assertIn ( expected_output_1 , output )
self . assertIn ( expected_output_2 , output )
2019-02-03 23:01:30 +01:00
def test_entries_since_100_days ( self ) :
2022-08-07 14:57:30 -04:00
""" Test showing log entries since 100 days """
2019-02-03 23:01:30 +01:00
expected_return_code = 0
expected_output_has = ' AppArmor denials: 20 (since '
2024-02-21 16:53:35 -03:00
return_code , output = cmd ( aanotify_bin + [ ' -f ' , self . test_logfile_current , ' -s ' , ' 100 ' ] )
2023-02-19 16:26:14 -05:00
result = ' Got return code {} , expected {} \n ' . format ( return_code , expected_return_code )
2019-02-03 23:01:30 +01:00
self . assertEqual ( expected_return_code , return_code , result + output )
2023-02-19 16:26:14 -05:00
result = ' Got output " {} " , expected " {} " \n ' . format ( output , expected_output_has )
2019-02-03 23:01:30 +01:00
self . assertIn ( expected_output_has , output , result + output )
2020-10-02 23:58:53 +02:00
@unittest.skipUnless ( os . path . isfile ( ' /var/log/wtmp ' ) , ' Requires wtmp on system ' )
2019-02-03 23:01:30 +01:00
def test_entries_since_login ( self ) :
2022-08-07 14:57:30 -04:00
""" Test showing log entries since last login """
2019-02-03 23:01:30 +01:00
expected_return_code = 0
expected_output_has = ' AppArmor denials: 10 (since '
2024-02-21 16:53:35 -03:00
return_code , output = cmd ( aanotify_bin + [ ' -f ' , self . test_logfile_last_login , ' -l ' ] )
2019-01-09 23:59:40 +01:00
if " ERROR: Could not find last login " in output :
2019-02-09 13:24:53 +02:00
self . skipTest ( ' Could not find last login ' )
2023-02-19 16:26:14 -05:00
result = ' Got return code {} , expected {} \n ' . format ( return_code , expected_return_code )
2019-02-03 23:01:30 +01:00
self . assertEqual ( expected_return_code , return_code , result + output )
2023-02-19 16:26:14 -05:00
result = ' Got output " {} " , expected " {} " \n ' . format ( output , expected_output_has )
2019-02-03 23:01:30 +01:00
self . assertIn ( expected_output_has , output , result + output )
2019-02-09 13:24:53 +02:00
@unittest.skipUnless ( os . path . isfile ( ' /var/log/wtmp ' ) , ' Requires wtmp on system ' )
2019-02-03 23:01:30 +01:00
def test_entries_since_login_verbose ( self ) :
2022-08-07 14:57:30 -04:00
""" Test showing log entries since last login in verbose mode """
2019-02-03 23:01:30 +01:00
expected_return_code = 0
expected_output_has = \
''' Profile: libreoffice-soffice
Operation : exec
Name : / bin / uname
Denied : x
Logfile : { logfile }
Profile : libreoffice - soffice / / null - / bin / uname
Operation : file_inherit
Name : / dev / null
Denied : w
Logfile : { logfile }
Profile : libreoffice - soffice / / null - / bin / uname
Operation : file_mmap
Name : / bin / uname
Denied : rm
Logfile : { logfile }
Profile : libreoffice - soffice / / null - / bin / uname
Operation : file_mmap
Name : / lib / x86_64 - linux - gnu / ld - 2.27 . so
Denied : rm
Logfile : { logfile }
Profile : libreoffice - soffice / / null - / bin / uname
Operation : open
Name : / etc / ld . so . cache
Denied : r
Logfile : { logfile }
Profile : libreoffice - soffice / / null - / bin / uname
Operation : open
Name : / lib / x86_64 - linux - gnu / libc - 2.27 . so
Denied : r
Logfile : { logfile }
Profile : libreoffice - soffice / / null - / bin / uname
Operation : file_mmap
Name : / lib / x86_64 - linux - gnu / libc - 2.27 . so
Denied : rm
Logfile : { logfile }
Profile : libreoffice - soffice / / null - / bin / uname
Operation : open
Name : / usr / lib / locale / locale - archive
Denied : r
Logfile : { logfile }
Profile : libreoffice - soffice
Operation : exec
Name : / usr / bin / file
Denied : x
Logfile : { logfile }
Profile : libreoffice - soffice / / null - / usr / bin / file
Operation : file_mmap
Name : / usr / bin / file
Denied : rm
Logfile : { logfile }
2024-05-17 13:53:42 +02:00
AppArmor denials : 10 ( since ''' .format(logfile=self.test_logfile_last_login) # noqa: E128
2019-02-03 23:01:30 +01:00
2024-02-21 16:53:35 -03:00
return_code , output = cmd ( aanotify_bin + [ ' -f ' , self . test_logfile_last_login , ' -l ' , ' -v ' ] )
2019-01-09 23:59:40 +01:00
if " ERROR: Could not find last login " in output :
2019-02-09 13:24:53 +02:00
self . skipTest ( ' Could not find last login ' )
2023-02-19 16:26:14 -05:00
result = ' Got return code {} , expected {} \n ' . format ( return_code , expected_return_code )
2019-02-03 23:01:30 +01:00
self . assertEqual ( expected_return_code , return_code , result + output )
2023-02-19 16:26:14 -05:00
result = ' Got output " {} " , expected " {} " \n ' . format ( output , expected_output_has )
2019-02-03 23:01:30 +01:00
self . assertIn ( expected_output_has , output , result + output )
2019-02-11 20:18:44 +02:00
2024-02-23 17:15:14 -03:00
class AANotifyProfileFilterTest ( AANotifyBase ) :
def test_profile_regex_since_100_days ( self ) :
profile_tests = (
( [ ' --filter.profile ' , ' libreoffice ' ] , ( 0 , ' AppArmor denials: 20 (since ' ) ) ,
( [ ' --filter.profile ' , ' libreoffice-soffice ' ] , ( 0 , ' AppArmor denials: 20 (since ' ) ) ,
( [ ' --filter.profile ' , ' libreoffice-soffice$ ' ] , ( 0 , ' AppArmor denials: 4 (since ' ) ) ,
( [ ' --filter.profile ' , ' ^libreoffice-soffice$ ' ] , ( 0 , ' AppArmor denials: 4 (since ' ) ) ,
( [ ' --filter.profile ' , ' libreoffice-soffice//null-/bin/uname ' ] , ( 0 , ' AppArmor denials: 14 (since ' ) ) ,
( [ ' --filter.profile ' , ' uname ' ] , ( 0 , ' AppArmor denials: 0 (since ' ) ) ,
( [ ' --filter.profile ' , ' .*uname ' ] , ( 0 , ' AppArmor denials: 14 (since ' ) ) ,
( [ ' --filter.profile ' , ' libreoffice-soffice//null-/.* ' ] , ( 0 , ' AppArmor denials: 16 (since ' ) ) ,
( [ ' --filter.profile ' , ' libreoffice-soffice//null-/foo ' ] , ( 0 , ' AppArmor denials: 0 (since ' ) ) ,
( [ ' --filter.profile ' , ' libreoffice-soffice/foo ' ] , ( 0 , ' AppArmor denials: 0 (since ' ) ) ,
( [ ' --filter.profile ' , ' bar ' ] , ( 0 , ' AppArmor denials: 0 (since ' ) ) ,
)
days_params = [ ' -f ' , self . test_logfile_current , ' -s ' , ' 100 ' ]
for test in profile_tests :
params = test [ 0 ]
expected = test [ 1 ]
with self . subTest ( params = params , expected = expected ) :
expected_return_code = expected [ 0 ]
expected_output_has = expected [ 1 ]
return_code , output = cmd ( aanotify_bin + days_params + params )
result = ' Got return code {} , expected {} \n ' . format ( return_code , expected_return_code )
self . assertEqual ( expected_return_code , return_code , result + output )
result = ' Got output " {} " , expected " {} " \n ' . format ( output , expected_output_has )
self . assertIn ( expected_output_has , output , result + output )
@unittest.skipUnless ( os . path . isfile ( ' /var/log/wtmp ' ) , ' Requires wtmp on system ' )
def test_profile_regex_since_login ( self ) :
profile_tests = (
( [ ' --filter.profile ' , ' libreoffice ' ] , ( 0 , ' AppArmor denials: 10 (since ' ) ) ,
( [ ' --filter.profile ' , ' libreoffice-soffice ' ] , ( 0 , ' AppArmor denials: 10 (since ' ) ) ,
( [ ' --filter.profile ' , ' libreoffice-soffice$ ' ] , ( 0 , ' AppArmor denials: 2 (since ' ) ) ,
( [ ' --filter.profile ' , ' ^libreoffice-soffice$ ' ] , ( 0 , ' AppArmor denials: 2 (since ' ) ) ,
( [ ' --filter.profile ' , ' libreoffice-soffice//null-/bin/uname ' ] , ( 0 , ' AppArmor denials: 7 (since ' ) ) ,
( [ ' --filter.profile ' , ' uname ' ] , ( 0 , ' AppArmor denials: 0 (since ' ) ) ,
( [ ' --filter.profile ' , ' .*uname ' ] , ( 0 , ' AppArmor denials: 7 (since ' ) ) ,
( [ ' --filter.profile ' , ' libreoffice-soffice//null-/.* ' ] , ( 0 , ' AppArmor denials: 8 (since ' ) ) ,
( [ ' --filter.profile ' , ' libreoffice-soffice//null-/foo ' ] , ( 0 , ' AppArmor denials: 0 (since ' ) ) ,
( [ ' --filter.profile ' , ' libreoffice-soffice/foo ' ] , ( 0 , ' AppArmor denials: 0 (since ' ) ) ,
( [ ' --filter.profile ' , ' bar ' ] , ( 0 , ' AppArmor denials: 0 (since ' ) ) ,
)
login_params = [ ' -f ' , self . test_logfile_last_login , ' -l ' ]
for test in profile_tests :
params = test [ 0 ]
expected = test [ 1 ]
with self . subTest ( params = params , expected = expected ) :
expected_return_code = expected [ 0 ]
expected_output_has = expected [ 1 ]
return_code , output = cmd ( aanotify_bin + login_params + params )
if ' ERROR: Could not find last login ' in output :
self . skipTest ( ' Could not find last login ' )
result = ' Got return code {} , expected {} \n ' . format ( return_code , expected_return_code )
self . assertEqual ( expected_return_code , return_code , result + output )
result = ' Got output " {} " , expected " {} " \n ' . format ( output , expected_output_has )
self . assertIn ( expected_output_has , output , result + output )
class AANotifyOperationFilterTest ( AANotifyBase ) :
def test_operation_regex_since_100_days ( self ) :
operation_tests = (
( [ ' --filter.operation ' , ' exec ' ] , ( 0 , ' AppArmor denials: 4 (since ' ) ) ,
( [ ' --filter.operation ' , ' file_inherit ' ] , ( 0 , ' AppArmor denials: 2 (since ' ) ) ,
( [ ' --filter.operation ' , ' file_mmap ' ] , ( 0 , ' AppArmor denials: 8 (since ' ) ) ,
( [ ' --filter.operation ' , ' open ' ] , ( 0 , ' AppArmor denials: 6 (since ' ) ) ,
( [ ' --filter.operation ' , ' file.* ' ] , ( 0 , ' AppArmor denials: 10 (since ' ) ) ,
( [ ' --filter.operation ' , ' profile_load ' ] , ( 0 , ' AppArmor denials: 0 (since ' ) ) ,
( [ ' --filter.operation ' , ' profile_replace ' ] , ( 0 , ' AppArmor denials: 0 (since ' ) ) ,
( [ ' --filter.operation ' , ' bar ' ] , ( 0 , ' AppArmor denials: 0 (since ' ) ) ,
( [ ' --filter.operation ' , ' userns_create ' ] , ( 0 , ' AppArmor denials: 0 (since ' ) ) ,
)
days_params = [ ' -f ' , self . test_logfile_current , ' -s ' , ' 100 ' ]
for test in operation_tests :
params = test [ 0 ]
expected = test [ 1 ]
with self . subTest ( params = params , expected = expected ) :
expected_return_code = expected [ 0 ]
expected_output_has = expected [ 1 ]
return_code , output = cmd ( aanotify_bin + days_params + params )
result = ' Got return code {} , expected {} \n ' . format ( return_code , expected_return_code )
self . assertEqual ( expected_return_code , return_code , result + output )
result = ' Got output " {} " , expected " {} " \n ' . format ( output , expected_output_has )
self . assertIn ( expected_output_has , output , result + output )
@unittest.skipUnless ( os . path . isfile ( ' /var/log/wtmp ' ) , ' Requires wtmp on system ' )
def test_operation_regex_since_login ( self ) :
operation_tests = (
( [ ' --filter.operation ' , ' exec ' ] , ( 0 , ' AppArmor denials: 2 (since ' ) ) ,
( [ ' --filter.operation ' , ' file_inherit ' ] , ( 0 , ' AppArmor denials: 1 (since ' ) ) ,
( [ ' --filter.operation ' , ' file_mmap ' ] , ( 0 , ' AppArmor denials: 4 (since ' ) ) ,
( [ ' --filter.operation ' , ' open ' ] , ( 0 , ' AppArmor denials: 3 (since ' ) ) ,
( [ ' --filter.operation ' , ' file.* ' ] , ( 0 , ' AppArmor denials: 5 (since ' ) ) ,
( [ ' --filter.operation ' , ' profile_load ' ] , ( 0 , ' AppArmor denials: 0 (since ' ) ) ,
( [ ' --filter.operation ' , ' profile_replace ' ] , ( 0 , ' AppArmor denials: 0 (since ' ) ) ,
( [ ' --filter.operation ' , ' bar ' ] , ( 0 , ' AppArmor denials: 0 (since ' ) ) ,
( [ ' --filter.operation ' , ' userns_create ' ] , ( 0 , ' AppArmor denials: 0 (since ' ) ) ,
)
login_params = [ ' -f ' , self . test_logfile_last_login , ' -l ' ]
for test in operation_tests :
params = test [ 0 ]
expected = test [ 1 ]
with self . subTest ( params = params , expected = expected ) :
expected_return_code = expected [ 0 ]
expected_output_has = expected [ 1 ]
return_code , output = cmd ( aanotify_bin + login_params + params )
if ' ERROR: Could not find last login ' in output :
self . skipTest ( ' Could not find last login ' )
result = ' Got return code {} , expected {} \n ' . format ( return_code , expected_return_code )
self . assertEqual ( expected_return_code , return_code , result + output )
result = ' Got output " {} " , expected " {} " \n ' . format ( output , expected_output_has )
self . assertIn ( expected_output_has , output , result + output )
class AANotifyNameFilterTest ( AANotifyBase ) :
def test_name_regex_since_100_days ( self ) :
name_tests = (
( [ ' --filter.name ' , ' /bin/uname ' ] , ( 0 , ' AppArmor denials: 4 (since ' ) ) ,
( [ ' --filter.name ' , ' /dev/null ' ] , ( 0 , ' AppArmor denials: 2 (since ' ) ) ,
( [ ' --filter.name ' , ' /lib/x86_64-linux-gnu/ld-2.27.so ' ] , ( 0 , ' AppArmor denials: 2 (since ' ) ) ,
( [ ' --filter.name ' , ' /lib/x86_64-linux-gnu/libc-2.27.so ' ] , ( 0 , ' AppArmor denials: 4 (since ' ) ) ,
( [ ' --filter.name ' , ' /etc/ld.so.cache ' ] , ( 0 , ' AppArmor denials: 2 (since ' ) ) ,
( [ ' --filter.name ' , ' /usr/lib/locale/locale-archive ' ] , ( 0 , ' AppArmor denials: 2 (since ' ) ) ,
( [ ' --filter.name ' , ' /usr/bin/file ' ] , ( 0 , ' AppArmor denials: 4 (since ' ) ) ,
( [ ' --filter.name ' , ' / ' ] , ( 0 , ' AppArmor denials: 20 (since ' ) ) ,
( [ ' --filter.name ' , ' /.* ' ] , ( 0 , ' AppArmor denials: 20 (since ' ) ) ,
( [ ' --filter.name ' , ' .*bin.* ' ] , ( 0 , ' AppArmor denials: 8 (since ' ) ) ,
( [ ' --filter.name ' , ' /(usr/)?bin.* ' ] , ( 0 , ' AppArmor denials: 8 (since ' ) ) ,
( [ ' --filter.name ' , ' /foo ' ] , ( 0 , ' AppArmor denials: 0 (since ' ) ) ,
)
days_params = [ ' -f ' , self . test_logfile_current , ' -s ' , ' 100 ' ]
for test in name_tests :
params = test [ 0 ]
expected = test [ 1 ]
with self . subTest ( params = params , expected = expected ) :
expected_return_code = expected [ 0 ]
expected_output_has = expected [ 1 ]
return_code , output = cmd ( aanotify_bin + days_params + params )
result = ' Got return code {} , expected {} \n ' . format ( return_code , expected_return_code )
self . assertEqual ( expected_return_code , return_code , result + output )
result = ' Got output " {} " , expected " {} " \n ' . format ( output , expected_output_has )
self . assertIn ( expected_output_has , output , result + output )
@unittest.skipUnless ( os . path . isfile ( ' /var/log/wtmp ' ) , ' Requires wtmp on system ' )
def test_name_regex_since_login ( self ) :
name_tests = (
( [ ' --filter.name ' , ' /bin/uname ' ] , ( 0 , ' AppArmor denials: 2 (since ' ) ) ,
( [ ' --filter.name ' , ' /dev/null ' ] , ( 0 , ' AppArmor denials: 1 (since ' ) ) ,
( [ ' --filter.name ' , ' /lib/x86_64-linux-gnu/ld-2.27.so ' ] , ( 0 , ' AppArmor denials: 1 (since ' ) ) ,
( [ ' --filter.name ' , ' /lib/x86_64-linux-gnu/libc-2.27.so ' ] , ( 0 , ' AppArmor denials: 2 (since ' ) ) ,
( [ ' --filter.name ' , ' /etc/ld.so.cache ' ] , ( 0 , ' AppArmor denials: 1 (since ' ) ) ,
( [ ' --filter.name ' , ' /usr/lib/locale/locale-archive ' ] , ( 0 , ' AppArmor denials: 1 (since ' ) ) ,
( [ ' --filter.name ' , ' /usr/bin/file ' ] , ( 0 , ' AppArmor denials: 2 (since ' ) ) ,
( [ ' --filter.name ' , ' / ' ] , ( 0 , ' AppArmor denials: 10 (since ' ) ) ,
( [ ' --filter.name ' , ' /.* ' ] , ( 0 , ' AppArmor denials: 10 (since ' ) ) ,
( [ ' --filter.name ' , ' .*bin.* ' ] , ( 0 , ' AppArmor denials: 4 (since ' ) ) ,
( [ ' --filter.name ' , ' /(usr/)?bin.* ' ] , ( 0 , ' AppArmor denials: 4 (since ' ) ) ,
( [ ' --filter.name ' , ' /foo ' ] , ( 0 , ' AppArmor denials: 0 (since ' ) ) ,
)
login_params = [ ' -f ' , self . test_logfile_last_login , ' -l ' ]
for test in name_tests :
params = test [ 0 ]
expected = test [ 1 ]
with self . subTest ( params = params , expected = expected ) :
expected_return_code = expected [ 0 ]
expected_output_has = expected [ 1 ]
return_code , output = cmd ( aanotify_bin + login_params + params )
if ' ERROR: Could not find last login ' in output :
self . skipTest ( ' Could not find last login ' )
result = ' Got return code {} , expected {} \n ' . format ( return_code , expected_return_code )
self . assertEqual ( expected_return_code , return_code , result + output )
result = ' Got output " {} " , expected " {} " \n ' . format ( output , expected_output_has )
self . assertIn ( expected_output_has , output , result + output )
class AANotifyDeniedFilterTest ( AANotifyBase ) :
def test_denied_regex_since_100_days ( self ) :
denied_tests = (
( [ ' --filter.denied ' , ' x ' ] , ( 0 , ' AppArmor denials: 4 (since ' ) ) ,
( [ ' --filter.denied ' , ' w ' ] , ( 0 , ' AppArmor denials: 2 (since ' ) ) ,
( [ ' --filter.denied ' , ' rm ' ] , ( 0 , ' AppArmor denials: 8 (since ' ) ) ,
( [ ' --filter.denied ' , ' r ' ] , ( 0 , ' AppArmor denials: 14 (since ' ) ) ,
( [ ' --filter.denied ' , ' ^r$ ' ] , ( 0 , ' AppArmor denials: 6 (since ' ) ) ,
( [ ' --filter.denied ' , ' x|w ' ] , ( 0 , ' AppArmor denials: 6 (since ' ) ) ,
( [ ' --filter.denied ' , ' ^(?!rm).* ' ] , ( 0 , ' AppArmor denials: 12 (since ' ) ) ,
( [ ' --filter.denied ' , ' .(?!m).* ' ] , ( 0 , ' AppArmor denials: 12 (since ' ) ) ,
( [ ' --filter.denied ' , ' r.? ' ] , ( 0 , ' AppArmor denials: 14 (since ' ) ) ,
)
days_params = [ ' -f ' , self . test_logfile_current , ' -s ' , ' 100 ' ]
for test in denied_tests :
params = test [ 0 ]
expected = test [ 1 ]
with self . subTest ( params = params , expected = expected ) :
expected_return_code = expected [ 0 ]
expected_output_has = expected [ 1 ]
return_code , output = cmd ( aanotify_bin + days_params + params )
result = ' Got return code {} , expected {} \n ' . format ( return_code , expected_return_code )
self . assertEqual ( expected_return_code , return_code , result + output )
result = ' Got output " {} " , expected " {} " \n ' . format ( output , expected_output_has )
self . assertIn ( expected_output_has , output , result + output )
@unittest.skipUnless ( os . path . isfile ( ' /var/log/wtmp ' ) , ' Requires wtmp on system ' )
def test_denied_regex_since_login ( self ) :
denied_tests = (
( [ ' --filter.denied ' , ' x ' ] , ( 0 , ' AppArmor denials: 2 (since ' ) ) ,
( [ ' --filter.denied ' , ' w ' ] , ( 0 , ' AppArmor denials: 1 (since ' ) ) ,
( [ ' --filter.denied ' , ' rm ' ] , ( 0 , ' AppArmor denials: 4 (since ' ) ) ,
( [ ' --filter.denied ' , ' r ' ] , ( 0 , ' AppArmor denials: 7 (since ' ) ) ,
( [ ' --filter.denied ' , ' ^r$ ' ] , ( 0 , ' AppArmor denials: 3 (since ' ) ) ,
( [ ' --filter.denied ' , ' x|w ' ] , ( 0 , ' AppArmor denials: 3 (since ' ) ) ,
( [ ' --filter.denied ' , ' ^(?!rm).* ' ] , ( 0 , ' AppArmor denials: 6 (since ' ) ) ,
( [ ' --filter.denied ' , ' .(?!m).* ' ] , ( 0 , ' AppArmor denials: 6 (since ' ) ) ,
( [ ' --filter.denied ' , ' r.? ' ] , ( 0 , ' AppArmor denials: 7 (since ' ) ) ,
)
login_params = [ ' -f ' , self . test_logfile_last_login , ' -l ' ]
for test in denied_tests :
params = test [ 0 ]
expected = test [ 1 ]
with self . subTest ( params = params , expected = expected ) :
expected_return_code = expected [ 0 ]
expected_output_has = expected [ 1 ]
return_code , output = cmd ( aanotify_bin + login_params + params )
if ' ERROR: Could not find last login ' in output :
self . skipTest ( ' Could not find last login ' )
result = ' Got return code {} , expected {} \n ' . format ( return_code , expected_return_code )
self . assertEqual ( expected_return_code , return_code , result + output )
result = ' Got output " {} " , expected " {} " \n ' . format ( output , expected_output_has )
self . assertIn ( expected_output_has , output , result + output )
2019-02-11 20:18:44 +02:00
setup_aa ( aa ) # Wrapper for aa.init_aa()
setup_all_loops ( __name__ )
2019-02-03 23:01:30 +01:00
if __name__ == ' __main__ ' :
if ' APPARMOR_NOTIFY ' in os . environ :
2025-01-22 11:52:38 -08:00
aanotify_bin = [ os . environ [ ' APPARMOR_NOTIFY ' ] ]
2020-10-25 16:46:07 +01:00
2025-01-22 12:04:35 -08:00
if sys . executable :
aanotify_bin = [ sys . executable ] + aanotify_bin
2020-10-25 16:46:07 +01:00
if ' __AA_CONFDIR ' in os . environ :
aanotify_bin = aanotify_bin + [ ' --configdir ' , os . getenv ( ' __AA_CONFDIR ' ) ]
2019-02-03 23:01:30 +01:00
unittest . main ( verbosity = 1 )