2016-10-01 20:57:09 +02:00
#! /usr/bin/python3
2014-11-27 23:20:26 +01:00
# ------------------------------------------------------------------
#
2024-10-06 20:39:01 +02:00
# Copyright (C) 2014-2024 Christian Boltz
2014-11-27 23:20:26 +01:00
#
# 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.
#
# ------------------------------------------------------------------
2015-10-20 23:16:41 +02:00
import os
2016-10-01 19:55:58 +02:00
import shutil
2022-08-07 20:32:07 -04:00
import unittest
2015-10-20 23:16:41 +02:00
2016-02-21 21:48:09 +01:00
import apparmor . aa # needed to set global vars in some tests
2022-08-07 12:26:24 -04:00
from apparmor . aa import (
2024-03-31 18:53:12 +02:00
change_profile_flags , check_for_apparmor , create_new_profile , get_file_perms , get_interpreter_and_abstraction , get_profile_flags ,
2024-11-01 22:05:48 +01:00
merged_to_split , parse_profile_data , propose_file_rules , set_options_audit_mode , set_options_owner_mode )
2016-10-01 20:04:42 +02:00
from apparmor . aare import AARE
2022-08-07 20:32:07 -04:00
from apparmor . common import AppArmorBug , AppArmorException , is_skippable_file
2016-10-01 20:03:44 +02:00
from apparmor . rule . file import FileRule
2020-05-13 21:45:00 +02:00
from apparmor . rule . include import IncludeRule
2022-08-07 20:32:07 -04:00
from common_test import AATest , read_file , setup_aa , setup_all_loops , write_file
2014-11-27 23:20:26 +01:00
2022-08-07 12:26:24 -04:00
2015-04-01 23:48:50 +02:00
class AaTestWithTempdir ( AATest ) :
2015-05-29 12:55:38 +02:00
def AASetup ( self ) :
self . createTmpdir ( )
2015-03-02 19:36:20 +01:00
class AaTest_check_for_apparmor ( AaTestWithTempdir ) :
2014-11-27 23:20:26 +01:00
FILESYSTEMS_WITH_SECURITYFS = ' nodev \t devtmpfs \n nodev \t securityfs \n nodev \t sockfs \n \t ext3 \n \t ext2 \n \t ext4 '
FILESYSTEMS_WITHOUT_SECURITYFS = ' nodev \t devtmpfs \n nodev \t sockfs \n \t ext3 \n \t ext2 \n \t ext4 '
2022-08-07 12:26:24 -04:00
MOUNTS_WITH_SECURITYFS = (
' proc /proc proc rw,relatime 0 0 \n '
2014-11-27 23:20:26 +01:00
' securityfs %s /security securityfs rw,nosuid,nodev,noexec,relatime 0 0 \n '
2022-08-07 12:26:24 -04:00
' /dev/sda1 / ext3 rw,noatime,data=ordered 0 0 ' )
2014-11-27 23:20:26 +01:00
2022-08-07 12:26:24 -04:00
MOUNTS_WITHOUT_SECURITYFS = (
' proc /proc proc rw,relatime 0 0 \n '
' /dev/sda1 / ext3 rw,noatime,data=ordered 0 0 ' )
2014-11-27 23:20:26 +01:00
def test_check_for_apparmor_None_1 ( self ) :
filesystems = write_file ( self . tmpdir , ' filesystems ' , self . FILESYSTEMS_WITHOUT_SECURITYFS )
mounts = write_file ( self . tmpdir , ' mounts ' , self . MOUNTS_WITH_SECURITYFS )
self . assertEqual ( None , check_for_apparmor ( filesystems , mounts ) )
def test_check_for_apparmor_None_2 ( self ) :
filesystems = write_file ( self . tmpdir , ' filesystems ' , self . FILESYSTEMS_WITHOUT_SECURITYFS )
mounts = write_file ( self . tmpdir , ' mounts ' , self . MOUNTS_WITHOUT_SECURITYFS )
self . assertEqual ( None , check_for_apparmor ( filesystems , mounts ) )
def test_check_for_apparmor_None_3 ( self ) :
filesystems = write_file ( self . tmpdir , ' filesystems ' , self . FILESYSTEMS_WITH_SECURITYFS )
mounts = write_file ( self . tmpdir , ' mounts ' , self . MOUNTS_WITHOUT_SECURITYFS )
self . assertEqual ( None , check_for_apparmor ( filesystems , mounts ) )
def test_check_for_apparmor_securityfs_invalid_filesystems ( self ) :
filesystems = ' '
2023-02-19 16:26:14 -05:00
mounts = write_file ( self . tmpdir , ' mounts ' , self . MOUNTS_WITH_SECURITYFS % ( self . tmpdir , ) )
2014-11-27 23:20:26 +01:00
self . assertEqual ( None , check_for_apparmor ( filesystems , mounts ) )
def test_check_for_apparmor_securityfs_invalid_mounts ( self ) :
filesystems = write_file ( self . tmpdir , ' filesystems ' , self . FILESYSTEMS_WITH_SECURITYFS )
mounts = ' '
self . assertEqual ( None , check_for_apparmor ( filesystems , mounts ) )
def test_check_for_apparmor_invalid_securityfs_path ( self ) :
filesystems = write_file ( self . tmpdir , ' filesystems ' , self . FILESYSTEMS_WITH_SECURITYFS )
2023-02-19 16:26:14 -05:00
mounts = write_file ( self . tmpdir , ' mounts ' , self . MOUNTS_WITH_SECURITYFS % ( ' xxx ' , ) )
2014-11-27 23:20:26 +01:00
self . assertEqual ( None , check_for_apparmor ( filesystems , mounts ) )
def test_check_for_apparmor_securityfs_mounted ( self ) :
filesystems = write_file ( self . tmpdir , ' filesystems ' , self . FILESYSTEMS_WITH_SECURITYFS )
2023-02-19 16:26:14 -05:00
mounts = write_file ( self . tmpdir , ' mounts ' , self . MOUNTS_WITH_SECURITYFS % ( self . tmpdir , ) )
self . assertEqual ( self . tmpdir + ' /security/apparmor ' , check_for_apparmor ( filesystems , mounts ) )
2014-11-27 23:20:26 +01:00
2022-08-07 12:26:24 -04:00
2015-10-20 23:14:42 +02:00
class AaTest_create_new_profile ( AATest ) :
2022-06-18 14:30:49 -04:00
tests = (
2022-08-07 12:26:24 -04:00
# file content filename expected interpreter expected abstraction (besides 'base') expected profiles
( ( ' #!/bin/bash \n true ' , ' script ' ) , ( u ' /bin/bash ' , ' abstractions/bash ' , [ ' script ' ] ) ) ,
( ( ' foo bar ' , ' fake_binary ' ) , ( None , None , [ ' fake_binary ' ] ) ) ,
( ( ' hats expected ' , ' apache2 ' ) , ( None , None , [ ' apache2 ' , ' apache2//DEFAULT_URI ' , ' apache2//HANDLING_UNTRUSTED_INPUT ' ] ) ) ,
2022-06-18 14:30:49 -04:00
)
2022-08-07 12:26:24 -04:00
2015-10-20 23:14:42 +02:00
def _run_test ( self , params , expected ) :
2016-10-01 19:55:58 +02:00
self . createTmpdir ( )
2022-08-07 12:26:24 -04:00
# copy the local profiles to the test directory
2023-02-19 16:26:14 -05:00
self . profile_dir = self . tmpdir + ' /profiles '
2016-10-01 19:55:58 +02:00
shutil . copytree ( ' ../../profiles/apparmor.d/ ' , self . profile_dir , symlinks = True )
# load the abstractions we need in the test
2020-06-01 15:54:34 +02:00
apparmor . aa . profile_dir = self . profile_dir
2020-06-01 17:03:52 +02:00
apparmor . aa . load_include ( os . path . join ( self . profile_dir , ' abstractions/base ' ) )
apparmor . aa . load_include ( os . path . join ( self . profile_dir , ' abstractions/bash ' ) )
2016-10-01 19:55:58 +02:00
2021-04-09 00:12:18 +02:00
exp_interpreter_path , exp_abstraction , exp_profiles = expected
2019-02-01 00:27:17 -08:00
# damn symlinks!
if exp_interpreter_path :
exp_interpreter_path = os . path . realpath ( exp_interpreter_path )
2015-10-20 23:14:42 +02:00
2021-04-09 00:12:18 +02:00
file_content , filename = params
program = self . writeTmpfile ( filename , file_content )
2015-10-20 23:14:42 +02:00
profile = create_new_profile ( program )
2021-04-09 00:12:18 +02:00
expected_profiles = [ ]
for prof in exp_profiles :
2023-02-19 16:26:14 -05:00
expected_profiles . append ( ' {} / {} ' . format ( self . tmpdir , prof ) ) # actual profile names start with tmpdir, prepend it to the expected profile names
2021-04-09 00:12:18 +02:00
self . assertEqual ( list ( profile . keys ( ) ) , expected_profiles )
2021-04-08 23:42:56 +02:00
2015-10-20 23:14:42 +02:00
if exp_interpreter_path :
2022-08-07 12:26:24 -04:00
self . assertEqual (
set ( profile [ program ] [ ' file ' ] . get_clean ( ) ) ,
2024-05-17 13:53:42 +02:00
{ ' {} ix, ' . format ( exp_interpreter_path ) , ' {} r, ' . format ( program ) , ' ' } )
2015-10-20 23:14:42 +02:00
else :
2023-02-19 16:26:14 -05:00
self . assertEqual ( set ( profile [ program ] [ ' file ' ] . get_clean ( ) ) , { ' {} mr, ' . format ( program ) , ' ' } )
2015-10-20 23:14:42 +02:00
if exp_abstraction :
2023-02-19 16:26:14 -05:00
self . assertEqual ( profile [ program ] [ ' inc_ie ' ] . get_clean ( ) , [ ' include <abstractions/base> ' , ' include < {} > ' . format ( exp_abstraction ) , ' ' ] )
2015-10-20 23:14:42 +02:00
else :
2021-04-08 23:42:56 +02:00
self . assertEqual ( profile [ program ] [ ' inc_ie ' ] . get_clean ( ) , [ ' include <abstractions/base> ' , ' ' ] )
2015-10-20 23:14:42 +02:00
2022-08-07 12:26:24 -04:00
2015-10-20 23:16:41 +02:00
class AaTest_get_interpreter_and_abstraction ( AATest ) :
2022-06-18 14:30:49 -04:00
tests = (
2022-08-07 12:26:24 -04:00
( ' #!/bin/bash ' , ( ' /bin/bash ' , ' abstractions/bash ' ) ) ,
( ' #!/bin/dash ' , ( ' /bin/dash ' , ' abstractions/bash ' ) ) ,
( ' #!/bin/sh ' , ( ' /bin/sh ' , ' abstractions/bash ' ) ) ,
( ' #! /bin/sh ' , ( ' /bin/sh ' , ' abstractions/bash ' ) ) ,
( ' #! /bin/sh -x ' , ( ' /bin/sh ' , ' abstractions/bash ' ) ) , # '-x' is not part of the interpreter path
( ' #!/usr/bin/perl ' , ( ' /usr/bin/perl ' , ' abstractions/perl ' ) ) ,
( ' #!/usr/bin/perl -w ' , ( ' /usr/bin/perl ' , ' abstractions/perl ' ) ) , # '-w' is not part of the interpreter path
( ' #!/usr/bin/python ' , ( ' /usr/bin/python ' , ' abstractions/python ' ) ) ,
( ' #!/usr/bin/python2 ' , ( ' /usr/bin/python2 ' , ' abstractions/python ' ) ) ,
( ' #!/usr/bin/python2.7 ' , ( ' /usr/bin/python2.7 ' , ' abstractions/python ' ) ) ,
( ' #!/usr/bin/python3 ' , ( ' /usr/bin/python3 ' , ' abstractions/python ' ) ) ,
( ' #!/usr/bin/python4 ' , ( ' /usr/bin/python4 ' , None ) ) , # python abstraction is only applied to py2 and py3
( ' #!/usr/bin/ruby ' , ( ' /usr/bin/ruby ' , ' abstractions/ruby ' ) ) ,
( ' #!/usr/bin/ruby2.2 ' , ( ' /usr/bin/ruby2.2 ' , ' abstractions/ruby ' ) ) ,
( ' #!/usr/bin/ruby1.9.1 ' , ( ' /usr/bin/ruby1.9.1 ' , ' abstractions/ruby ' ) ) ,
( ' #!/usr/bin/foobarbaz ' , ( ' /usr/bin/foobarbaz ' , None ) ) , # we don't have an abstraction for "foobarbaz"
( ' foo ' , ( None , None ) ) , # no hashbang - not a script
2022-06-18 14:30:49 -04:00
)
2015-10-20 23:16:41 +02:00
def _run_test ( self , params , expected ) :
exp_interpreter_path , exp_abstraction = expected
2023-02-19 16:26:14 -05:00
program = self . writeTmpfile ( ' program ' , params + " \n foo \n bar " )
2015-10-20 23:16:41 +02:00
interpreter_path , abstraction = get_interpreter_and_abstraction ( program )
# damn symlinks!
2019-02-01 00:27:17 -08:00
if exp_interpreter_path :
exp_interpreter_path = os . path . realpath ( exp_interpreter_path )
2015-10-20 23:16:41 +02:00
self . assertEqual ( interpreter_path , exp_interpreter_path )
self . assertEqual ( abstraction , exp_abstraction )
def test_special_file ( self ) :
self . assertEqual ( ( None , None ) , get_interpreter_and_abstraction ( ' /dev/null ' ) )
def test_file_not_found ( self ) :
self . createTmpdir ( )
2023-02-19 16:26:14 -05:00
self . assertEqual ( ( None , None ) , get_interpreter_and_abstraction ( self . tmpdir + ' /file-not-found ' ) )
2015-10-20 23:16:41 +02:00
2015-03-02 19:36:20 +01:00
class AaTest_get_profile_flags ( AaTestWithTempdir ) :
def _test_get_flags ( self , profile_header , expected_flags ) :
2023-02-19 16:26:14 -05:00
file = write_file ( self . tmpdir , ' profile ' , profile_header + ' { \n } \n ' )
2015-03-02 19:36:20 +01:00
flags = get_profile_flags ( file , ' /foo ' )
self . assertEqual ( flags , expected_flags )
def test_get_flags_01 ( self ) :
self . _test_get_flags ( ' /foo ' , None )
2024-05-17 13:53:42 +02:00
2015-03-02 19:36:20 +01:00
def test_get_flags_02 ( self ) :
self . _test_get_flags ( ' /foo ( complain ) ' , ' complain ' )
2024-05-17 13:53:42 +02:00
2015-03-02 19:36:20 +01:00
def test_get_flags_04 ( self ) :
self . _test_get_flags ( ' /foo (complain) ' , ' complain ' )
2024-05-17 13:53:42 +02:00
2015-03-02 19:36:20 +01:00
def test_get_flags_05 ( self ) :
self . _test_get_flags ( ' /foo flags=(complain) ' , ' complain ' )
2024-05-17 13:53:42 +02:00
2015-03-02 19:36:20 +01:00
def test_get_flags_06 ( self ) :
self . _test_get_flags ( ' /foo flags=(complain, audit) ' , ' complain, audit ' )
def test_get_flags_invalid_01 ( self ) :
2015-04-03 17:28:03 +02:00
with self . assertRaises ( AppArmorException ) :
2015-03-02 19:36:20 +01:00
self . _test_get_flags ( ' /foo () ' , None )
2024-05-17 13:53:42 +02:00
2015-03-02 19:36:20 +01:00
def test_get_flags_invalid_02 ( self ) :
2015-04-03 17:28:03 +02:00
with self . assertRaises ( AppArmorException ) :
2015-03-02 19:36:20 +01:00
self . _test_get_flags ( ' /foo flags=() ' , None )
2024-05-17 13:53:42 +02:00
2015-03-02 19:36:20 +01:00
def test_get_flags_invalid_03 ( self ) :
with self . assertRaises ( AppArmorException ) :
self . _test_get_flags ( ' /foo ( ) ' , ' ' )
def test_get_flags_other_profile ( self ) :
with self . assertRaises ( AppArmorException ) :
self . _test_get_flags ( ' /no-such-profile flags=(complain) ' , ' complain ' )
2022-08-07 12:26:24 -04:00
2018-07-25 22:20:48 +02:00
class AaTest_change_profile_flags ( AaTestWithTempdir ) :
2022-08-07 12:26:24 -04:00
def _test_change_profile_flags (
self , profile , old_flags , flags_to_change , set_flag , expected_flags , whitespace = ' ' ,
comment = ' ' , more_rules = ' ' , expected_more_rules = ' @-@-@ ' , check_new_flags = True , profile_name = ' /foo ' ) :
2015-04-01 23:43:29 +02:00
if old_flags :
2023-02-19 16:26:14 -05:00
old_flags = ' ' + old_flags
2015-04-01 23:43:29 +02:00
if expected_flags :
2023-02-19 16:26:14 -05:00
expected_flags = ' flags=( {} ) ' . format ( expected_flags )
2015-04-01 23:43:29 +02:00
else :
expected_flags = ' '
2015-05-28 22:14:37 +02:00
if expected_more_rules == ' @-@-@ ' :
expected_more_rules = more_rules
2015-04-03 17:20:14 +02:00
if comment :
2023-02-19 16:26:14 -05:00
comment = ' ' + comment
2015-04-03 17:20:14 +02:00
2015-04-01 23:43:29 +02:00
dummy_profile_content = ' #include <abstractions/base> \n capability chown, \n /bar r, '
prof_template = ' %s %s %s { %s \n %s \n %s \n } \n '
2015-05-28 22:14:37 +02:00
old_prof = prof_template % ( whitespace , profile , old_flags , comment , more_rules , dummy_profile_content )
2021-05-23 19:00:06 +02:00
new_prof = prof_template % ( ' ' , profile , expected_flags , comment , expected_more_rules , dummy_profile_content )
2015-04-01 23:43:29 +02:00
self . file = write_file ( self . tmpdir , ' profile ' , old_prof )
2018-07-25 22:20:48 +02:00
change_profile_flags ( self . file , profile_name , flags_to_change , set_flag )
2015-04-01 23:43:29 +02:00
if check_new_flags :
real_new_prof = read_file ( self . file )
self . assertEqual ( new_prof , real_new_prof )
# tests that actually don't change the flags
2018-07-25 22:20:48 +02:00
def test_change_profile_flags_nochange_02 ( self ) :
self . _test_change_profile_flags ( ' /foo ' , ' ( complain ) ' , ' complain ' , True , ' complain ' , whitespace = ' ' )
2024-05-17 13:53:42 +02:00
2018-07-25 22:20:48 +02:00
def test_change_profile_flags_nochange_03 ( self ) :
self . _test_change_profile_flags ( ' /foo ' , ' (complain) ' , ' complain ' , True , ' complain ' )
2024-05-17 13:53:42 +02:00
2018-07-25 22:20:48 +02:00
def test_change_profile_flags_nochange_04 ( self ) :
self . _test_change_profile_flags ( ' /foo ' , ' flags=(complain) ' , ' complain ' , True , ' complain ' )
2024-05-17 13:53:42 +02:00
2018-07-25 22:20:48 +02:00
def test_change_profile_flags_nochange_05 ( self ) :
self . _test_change_profile_flags ( ' /foo ' , ' flags=(complain, audit) ' , ' complain ' , True , ' audit, complain ' , whitespace = ' ' )
2024-05-17 13:53:42 +02:00
2018-07-25 22:20:48 +02:00
def test_change_profile_flags_nochange_06 ( self ) :
self . _test_change_profile_flags ( ' /foo ' , ' flags=(complain, audit) ' , ' complain ' , True , ' audit, complain ' , whitespace = ' ' , comment = ' # a comment ' )
2024-05-17 13:53:42 +02:00
2018-07-25 22:20:48 +02:00
def test_change_profile_flags_nochange_07 ( self ) :
self . _test_change_profile_flags ( ' /foo ' , ' flags=(complain, audit) ' , ' audit ' , True , ' audit, complain ' , whitespace = ' ' , more_rules = ' # a comment \n #another comment ' )
2024-05-17 13:53:42 +02:00
2018-07-25 22:20:48 +02:00
def test_change_profile_flags_nochange_08 ( self ) :
self . _test_change_profile_flags ( ' profile /foo ' , ' flags=(complain) ' , ' complain ' , True , ' complain ' )
2024-05-17 13:53:42 +02:00
2018-07-25 22:20:48 +02:00
def test_change_profile_flags_nochange_09 ( self ) :
self . _test_change_profile_flags ( ' profile xy /foo ' , ' flags=(complain) ' , ' complain ' , True , ' complain ' , profile_name = ' xy ' )
2024-05-17 13:53:42 +02:00
2018-07-25 22:20:48 +02:00
def test_change_profile_flags_nochange_10 ( self ) :
self . _test_change_profile_flags ( ' profile " /foo bar " ' , ' flags=(complain) ' , ' complain ' , True , ' complain ' , profile_name = ' /foo bar ' )
2024-05-17 13:53:42 +02:00
2018-07-25 22:20:48 +02:00
def test_change_profile_flags_nochange_11 ( self ) :
self . _test_change_profile_flags ( ' /foo ' , ' (complain) ' , ' complain ' , True , ' complain ' , profile_name = None )
2024-05-17 13:53:42 +02:00
2018-07-25 22:20:48 +02:00
def test_change_profile_flags_nochange_12 ( self ) :
# XXX changes the flags for the child profile (which happens to have the same profile name) to 'complain'
self . _test_change_profile_flags ( ' /foo ' , ' flags=(complain) ' , ' complain ' , True , ' complain ' , more_rules = ' profile /foo { \n } ' , expected_more_rules = ' profile /foo flags=(complain) { \n } ' )
2015-04-01 23:43:29 +02:00
# tests that change the flags
2018-07-25 22:20:48 +02:00
def test_change_profile_flags_01 ( self ) :
self . _test_change_profile_flags ( ' /foo ' , ' ' , ' audit ' , True , ' audit ' )
2024-05-17 13:53:42 +02:00
2018-07-25 22:20:48 +02:00
def test_change_profile_flags_02 ( self ) :
self . _test_change_profile_flags ( ' /foo ' , ' ( complain ) ' , ' audit ' , True , ' audit, complain ' , whitespace = ' ' )
2024-05-17 13:53:42 +02:00
2018-07-25 22:20:48 +02:00
def test_change_profile_flags_04 ( self ) :
self . _test_change_profile_flags ( ' /foo ' , ' (complain) ' , ' audit ' , True , ' audit, complain ' )
2024-05-17 13:53:42 +02:00
2018-07-25 22:20:48 +02:00
def test_change_profile_flags_05 ( self ) :
self . _test_change_profile_flags ( ' /foo ' , ' flags=(complain) ' , ' audit ' , True , ' audit, complain ' )
2024-05-17 13:53:42 +02:00
2018-07-25 22:20:48 +02:00
def test_change_profile_flags_06 ( self ) :
self . _test_change_profile_flags ( ' /foo ' , ' flags=(complain, audit) ' , ' complain ' , False , ' audit ' , whitespace = ' ' )
2024-05-17 13:53:42 +02:00
2018-07-25 22:20:48 +02:00
def test_change_profile_flags_07 ( self ) :
self . _test_change_profile_flags ( ' /foo ' , ' flags=(complain, audit) ' , ' audit ' , False , ' complain ' )
2024-05-17 13:53:42 +02:00
2018-07-25 22:20:48 +02:00
def test_change_profile_flags_08 ( self ) :
self . _test_change_profile_flags ( ' /foo ' , ' ( complain ) ' , ' audit ' , True , ' audit, complain ' , whitespace = ' ' , profile_name = None )
2024-05-17 13:53:42 +02:00
2018-07-25 22:20:48 +02:00
def test_change_profile_flags_09 ( self ) :
self . _test_change_profile_flags ( ' profile /foo ' , ' flags=(complain) ' , ' audit ' , True , ' audit, complain ' )
2024-05-17 13:53:42 +02:00
2018-07-25 22:20:48 +02:00
def test_change_profile_flags_10 ( self ) :
self . _test_change_profile_flags ( ' profile xy /foo ' , ' flags=(complain) ' , ' audit ' , True , ' audit, complain ' , profile_name = ' xy ' )
2024-05-17 13:53:42 +02:00
2018-07-25 22:20:48 +02:00
def test_change_profile_flags_11 ( self ) :
self . _test_change_profile_flags ( ' profile " /foo bar " ' , ' flags=(complain) ' , ' audit ' , True , ' audit, complain ' , profile_name = ' /foo bar ' )
2024-05-17 13:53:42 +02:00
2018-07-25 22:20:48 +02:00
def test_change_profile_flags_12 ( self ) :
self . _test_change_profile_flags ( ' profile xy " /foo bar " ' , ' flags=(complain) ' , ' audit ' , True , ' audit, complain ' , profile_name = ' xy ' )
2024-05-17 13:53:42 +02:00
2018-07-25 22:20:48 +02:00
def test_change_profile_flags_13 ( self ) :
self . _test_change_profile_flags ( ' /foo ' , ' (audit) ' , ' audit ' , False , ' ' )
2015-04-01 23:43:29 +02:00
2015-05-28 22:14:37 +02:00
# test handling of hat flags
def test_set_flags_with_hat_01 ( self ) :
2022-08-07 12:26:24 -04:00
self . _test_change_profile_flags (
' /foo ' , ' flags=(complain) ' , ' audit ' , True , ' audit, complain ' ,
2015-05-28 22:14:37 +02:00
more_rules = ' \n ^foobar { \n } \n ' ,
2018-07-25 23:22:33 +02:00
expected_more_rules = ' \n ^foobar flags=(audit) { \n } \n '
2015-05-28 22:14:37 +02:00
)
2018-07-25 22:20:48 +02:00
def test_change_profile_flags_with_hat_02 ( self ) :
2022-08-07 12:26:24 -04:00
self . _test_change_profile_flags (
' /foo ' , ' flags=(complain) ' , ' audit ' , False , ' complain ' ,
2015-05-28 22:14:37 +02:00
profile_name = None ,
2018-07-25 22:20:48 +02:00
more_rules = ' \n ^foobar flags=(audit) { \n } \n ' ,
2018-07-25 23:22:33 +02:00
expected_more_rules = ' \n ^foobar { \n } \n '
2015-05-28 22:14:37 +02:00
)
2018-07-25 22:20:48 +02:00
def test_change_profile_flags_with_hat_03 ( self ) :
2022-08-07 12:26:24 -04:00
self . _test_change_profile_flags (
' /foo ' , ' flags=(complain) ' , ' audit ' , True , ' audit, complain ' ,
2018-07-25 23:22:33 +02:00
more_rules = ' \n ^foobar (attach_disconnected) { # comment \n } \n ' ,
2021-05-23 19:00:06 +02:00
expected_more_rules = ' \n ^foobar flags=(attach_disconnected, audit) { # comment \n } \n '
2015-05-28 22:14:37 +02:00
)
2018-07-25 22:20:48 +02:00
def test_change_profile_flags_with_hat_04 ( self ) :
2022-08-07 12:26:24 -04:00
self . _test_change_profile_flags (
' /foo ' , ' ' , ' audit ' , True , ' audit ' ,
2018-07-25 23:22:33 +02:00
more_rules = ' \n hat foobar (attach_disconnected) { # comment \n } \n ' ,
expected_more_rules = ' \n hat foobar flags=(attach_disconnected, audit) { # comment \n } \n '
2015-05-28 22:14:37 +02:00
)
2018-07-25 22:20:48 +02:00
def test_change_profile_flags_with_hat_05 ( self ) :
2022-08-07 12:26:24 -04:00
self . _test_change_profile_flags (
' /foo ' , ' (audit) ' , ' audit ' , False , ' ' ,
2018-07-25 23:22:33 +02:00
more_rules = ' \n hat foobar (attach_disconnected) { # comment \n } \n ' ,
expected_more_rules = ' \n hat foobar flags=(attach_disconnected) { # comment \n } \n '
2015-06-26 23:21:29 +02:00
)
2015-05-28 22:14:37 +02:00
# test handling of child profiles
2018-07-25 22:20:48 +02:00
def test_change_profile_flags_with_child_01 ( self ) :
2022-08-07 12:26:24 -04:00
self . _test_change_profile_flags (
' /foo ' , ' flags=(complain) ' , ' audit ' , True , ' audit, complain ' ,
2015-05-28 22:14:37 +02:00
profile_name = None ,
more_rules = ' \n profile /bin/bar { \n } \n ' ,
2018-07-25 23:22:33 +02:00
expected_more_rules = ' \n profile /bin/bar flags=(audit) { \n } \n '
2015-05-28 22:14:37 +02:00
)
2018-07-25 22:20:48 +02:00
def test_change_profile_flags_with_child_02 ( self ) :
2015-05-28 22:14:37 +02:00
# XXX child profile flags aren't changed if profile parameter is not None
2022-08-07 12:26:24 -04:00
self . _test_change_profile_flags (
' /foo ' , ' flags=(complain) ' , ' audit ' , True , ' audit, complain ' ,
2018-07-25 22:20:48 +02:00
more_rules = ' \n profile /bin/bar { \n } \n ' ,
expected_more_rules = ' \n profile /bin/bar { \n } \n ' # flags(audit) should be added
)
def test_change_profile_flags_invalid_01 ( self ) :
2018-07-25 23:22:33 +02:00
with self . assertRaises ( AppArmorBug ) :
2018-07-25 22:20:48 +02:00
self . _test_change_profile_flags ( ' /foo ' , ' () ' , None , False , ' ' , check_new_flags = False )
2024-05-17 13:53:42 +02:00
2018-07-25 22:20:48 +02:00
def test_change_profile_flags_invalid_02 ( self ) :
2018-07-25 23:22:33 +02:00
with self . assertRaises ( AppArmorBug ) :
2018-07-25 22:20:48 +02:00
self . _test_change_profile_flags ( ' /foo ' , ' flags=() ' , None , True , ' ' , check_new_flags = False )
2024-05-17 13:53:42 +02:00
2018-07-25 22:20:48 +02:00
def test_change_profile_flags_invalid_03 ( self ) :
2018-07-25 23:22:33 +02:00
with self . assertRaises ( AppArmorBug ) :
2018-07-25 22:20:48 +02:00
self . _test_change_profile_flags ( ' /foo ' , ' ( ) ' , ' ' , True , ' ' , check_new_flags = False )
2024-05-17 13:53:42 +02:00
2018-07-25 22:20:48 +02:00
def test_change_profile_flags_invalid_04 ( self ) :
2018-07-25 22:30:13 +02:00
with self . assertRaises ( AppArmorBug ) :
2022-08-07 12:26:24 -04:00
self . _test_change_profile_flags ( ' /foo ' , ' flags=(complain, audit) ' , ' ' , True , ' audit, complain ' , check_new_flags = False ) # whitespace-only newflags
2015-04-01 23:43:29 +02:00
2018-07-25 22:20:48 +02:00
def test_change_profile_flags_other_profile ( self ) :
2015-04-01 23:43:29 +02:00
# test behaviour if the file doesn't contain the specified /foo profile
orig_prof = ' /no-such-profile flags=(complain) { \n } '
self . file = write_file ( self . tmpdir , ' profile ' , orig_prof )
2018-07-25 22:20:48 +02:00
with self . assertRaises ( AppArmorException ) :
change_profile_flags ( self . file , ' /foo ' , ' audit ' , True )
2015-04-03 17:25:18 +02:00
# the file should not be changed
real_new_prof = read_file ( self . file )
self . assertEqual ( orig_prof , real_new_prof )
2018-07-25 22:20:48 +02:00
def test_change_profile_flags_no_profile_found ( self ) :
2015-04-03 17:25:18 +02:00
# test behaviour if the file doesn't contain any profile
orig_prof = ' # /comment flags=(complain) { \n # } '
self . file = write_file ( self . tmpdir , ' profile ' , orig_prof )
2018-07-25 22:20:48 +02:00
with self . assertRaises ( AppArmorException ) :
change_profile_flags ( self . file , None , ' audit ' , True )
2015-04-01 23:43:29 +02:00
# the file should not be changed
real_new_prof = read_file ( self . file )
self . assertEqual ( orig_prof , real_new_prof )
2018-07-25 22:20:48 +02:00
def test_change_profile_flags_file_not_found ( self ) :
2015-04-03 17:20:14 +02:00
with self . assertRaises ( IOError ) :
2023-02-19 16:26:14 -05:00
change_profile_flags ( self . tmpdir + ' /file-not-found ' , ' /foo ' , ' audit ' , True )
2015-04-01 23:43:29 +02:00
2022-08-07 12:26:24 -04:00
2016-10-01 20:05:27 +02:00
class AaTest_set_options_audit_mode ( AATest ) :
2022-06-18 14:30:49 -04:00
tests = (
2022-09-10 19:45:22 -04:00
( ( FileRule . create_instance ( ' audit /foo/bar r, ' ) , [ ' /foo/bar r, ' , ' /foo/* r, ' , ' /** r, ' ] ) , [ ' audit /foo/bar r, ' , ' audit /foo/* r, ' , ' audit /** r, ' ] ) ,
( ( FileRule . create_instance ( ' audit /foo/bar r, ' ) , [ ' /foo/bar r, ' , ' audit /foo/* r, ' , ' audit /** r, ' ] ) , [ ' audit /foo/bar r, ' , ' audit /foo/* r, ' , ' audit /** r, ' ] ) ,
( ( FileRule . create_instance ( ' /foo/bar r, ' ) , [ ' /foo/bar r, ' , ' /foo/* r, ' , ' /** r, ' ] ) , [ ' /foo/bar r, ' , ' /foo/* r, ' , ' /** r, ' ] ) ,
( ( FileRule . create_instance ( ' /foo/bar r, ' ) , [ ' audit /foo/bar r, ' , ' audit /foo/* r, ' , ' audit /** r, ' ] ) , [ ' /foo/bar r, ' , ' /foo/* r, ' , ' /** r, ' ] ) ,
( ( FileRule . create_instance ( ' audit /foo/bar r, ' ) , [ ' /foo/bar r, ' , ' /foo/* r, ' , ' #include <abstractions/base> ' ] ) , [ ' audit /foo/bar r, ' , ' audit /foo/* r, ' , ' #include <abstractions/base> ' ] ) ,
2022-06-18 14:30:49 -04:00
)
2016-10-01 20:05:27 +02:00
def _run_test ( self , params , expected ) :
rule_obj , options = params
new_options = set_options_audit_mode ( rule_obj , options )
self . assertEqual ( new_options , expected )
2015-03-02 19:36:20 +01:00
2022-08-07 12:26:24 -04:00
2017-12-17 16:42:12 +01:00
class AaTest_set_options_owner_mode ( AATest ) :
2022-06-18 14:30:49 -04:00
tests = (
2022-09-10 19:45:22 -04:00
( ( FileRule . create_instance ( ' owner /foo/bar r, ' ) , [ ' /foo/bar r, ' , ' /foo/* r, ' , ' /** r, ' ] ) , [ ' owner /foo/bar r, ' , ' owner /foo/* r, ' , ' owner /** r, ' ] ) ,
( ( FileRule . create_instance ( ' owner /foo/bar r, ' ) , [ ' /foo/bar r, ' , ' owner /foo/* r, ' , ' owner /** r, ' ] ) , [ ' owner /foo/bar r, ' , ' owner /foo/* r, ' , ' owner /** r, ' ] ) ,
( ( FileRule . create_instance ( ' /foo/bar r, ' ) , [ ' /foo/bar r, ' , ' /foo/* r, ' , ' /** r, ' ] ) , [ ' /foo/bar r, ' , ' /foo/* r, ' , ' /** r, ' ] ) ,
( ( FileRule . create_instance ( ' /foo/bar r, ' ) , [ ' owner /foo/bar r, ' , ' owner /foo/* r, ' , ' owner /** r, ' ] ) , [ ' /foo/bar r, ' , ' /foo/* r, ' , ' /** r, ' ] ) ,
( ( FileRule . create_instance ( ' audit owner /foo/bar r, ' ) , [ ' audit /foo/bar r, ' , ' audit /foo/* r, ' , ' #include <abstractions/base> ' ] ) , [ ' audit owner /foo/bar r, ' , ' audit owner /foo/* r, ' , ' #include <abstractions/base> ' ] ) ,
2022-06-18 14:30:49 -04:00
)
2017-12-17 16:42:12 +01:00
def _run_test ( self , params , expected ) :
rule_obj , options = params
new_options = set_options_owner_mode ( rule_obj , options )
self . assertEqual ( new_options , expected )
2022-08-07 12:26:24 -04:00
2015-04-01 23:48:50 +02:00
class AaTest_is_skippable_file ( AATest ) :
2015-02-04 13:16:29 +01:00
def test_not_skippable_01 ( self ) :
self . assertFalse ( is_skippable_file ( ' bin.ping ' ) )
2024-05-17 13:53:42 +02:00
2015-02-04 13:16:29 +01:00
def test_not_skippable_02 ( self ) :
self . assertFalse ( is_skippable_file ( ' usr.lib.dovecot.anvil ' ) )
2024-05-17 13:53:42 +02:00
2015-02-04 13:16:29 +01:00
def test_not_skippable_03 ( self ) :
self . assertFalse ( is_skippable_file ( ' bin.~ping ' ) )
2024-05-17 13:53:42 +02:00
2015-02-04 13:16:29 +01:00
def test_not_skippable_04 ( self ) :
self . assertFalse ( is_skippable_file ( ' bin.rpmsave.ping ' ) )
2024-05-17 13:53:42 +02:00
2015-02-04 13:16:29 +01:00
def test_not_skippable_05 ( self ) :
# normally is_skippable_file should be called without directory, but it shouldn't hurt too much
self . assertFalse ( is_skippable_file ( ' /etc/apparmor.d/bin.ping ' ) )
2024-05-17 13:53:42 +02:00
2015-02-04 13:16:29 +01:00
def test_not_skippable_06 ( self ) :
self . assertFalse ( is_skippable_file ( ' bin.pingrej ' ) )
def test_skippable_01 ( self ) :
self . assertTrue ( is_skippable_file ( ' bin.ping.dpkg-new ' ) )
2024-05-17 13:53:42 +02:00
2015-02-04 13:16:29 +01:00
def test_skippable_02 ( self ) :
self . assertTrue ( is_skippable_file ( ' bin.ping.dpkg-old ' ) )
2024-05-17 13:53:42 +02:00
2015-02-04 13:16:29 +01:00
def test_skippable_03 ( self ) :
self . assertTrue ( is_skippable_file ( ' bin.ping..dpkg-dist ' ) )
2024-05-17 13:53:42 +02:00
2015-02-04 13:16:29 +01:00
def test_skippable_04 ( self ) :
self . assertTrue ( is_skippable_file ( ' bin.ping..dpkg-bak ' ) )
2024-05-17 13:53:42 +02:00
2015-02-04 13:16:29 +01:00
def test_skippable_05 ( self ) :
2018-03-30 18:05:06 +02:00
self . assertTrue ( is_skippable_file ( ' bin.ping.dpkg-remove ' ) )
2024-05-17 13:53:42 +02:00
2015-02-04 13:16:29 +01:00
def test_skippable_06 ( self ) :
2018-03-30 18:05:06 +02:00
self . assertTrue ( is_skippable_file ( ' bin.ping.pacsave ' ) )
2024-05-17 13:53:42 +02:00
2015-02-04 13:16:29 +01:00
def test_skippable_07 ( self ) :
2018-03-30 18:05:06 +02:00
self . assertTrue ( is_skippable_file ( ' bin.ping.pacnew ' ) )
2024-05-17 13:53:42 +02:00
2015-02-04 13:16:29 +01:00
def test_skippable_08 ( self ) :
2018-03-30 18:05:06 +02:00
self . assertTrue ( is_skippable_file ( ' bin.ping.rpmnew ' ) )
2024-05-17 13:53:42 +02:00
2015-02-04 13:16:29 +01:00
def test_skippable_09 ( self ) :
2018-03-30 18:05:06 +02:00
self . assertTrue ( is_skippable_file ( ' bin.ping.rpmsave ' ) )
2024-05-17 13:53:42 +02:00
2015-02-04 13:16:29 +01:00
def test_skippable_10 ( self ) :
2018-03-30 18:05:06 +02:00
self . assertTrue ( is_skippable_file ( ' bin.ping.orig ' ) )
2024-05-17 13:53:42 +02:00
2018-03-30 18:05:06 +02:00
def test_skippable_11 ( self ) :
2018-03-30 17:46:25 +02:00
self . assertTrue ( is_skippable_file ( ' bin.ping.rej ' ) )
2024-05-17 13:53:42 +02:00
2018-03-30 17:46:25 +02:00
def test_skippable_12 ( self ) :
2018-03-30 18:05:06 +02:00
self . assertTrue ( is_skippable_file ( ' bin.ping~ ' ) )
2024-05-17 13:53:42 +02:00
2018-03-30 17:46:25 +02:00
def test_skippable_13 ( self ) :
2018-03-30 18:05:06 +02:00
self . assertTrue ( is_skippable_file ( ' .bin.ping ' ) )
2024-05-17 13:53:42 +02:00
2018-03-30 17:46:25 +02:00
def test_skippable_14 ( self ) :
2018-03-30 18:05:06 +02:00
self . assertTrue ( is_skippable_file ( ' ' ) ) # empty filename
2024-05-17 13:53:42 +02:00
2018-03-30 17:46:25 +02:00
def test_skippable_15 ( self ) :
2018-03-30 18:05:06 +02:00
self . assertTrue ( is_skippable_file ( ' /etc/apparmor.d/ ' ) ) # directory without filename
2024-05-17 13:53:42 +02:00
2018-03-30 18:05:06 +02:00
def test_skippable_16 ( self ) :
2015-02-04 13:16:29 +01:00
self . assertTrue ( is_skippable_file ( ' README ' ) )
2022-08-07 12:26:24 -04:00
2015-05-29 13:00:32 +02:00
class AaTest_parse_profile_data ( AATest ) :
def test_parse_empty_profile_01 ( self ) :
2021-02-22 22:22:25 +01:00
prof = parse_profile_data ( ' /foo { \n } \n ' . split ( ) , ' somefile ' , False , False )
2015-05-29 13:00:32 +02:00
self . assertEqual ( list ( prof . keys ( ) ) , [ ' /foo ' ] )
2021-04-04 00:45:14 +02:00
self . assertEqual ( prof [ ' /foo ' ] [ ' name ' ] , ' /foo ' )
self . assertEqual ( prof [ ' /foo ' ] [ ' filename ' ] , ' somefile ' )
self . assertEqual ( prof [ ' /foo ' ] [ ' flags ' ] , None )
2015-05-29 13:00:32 +02:00
2024-10-06 20:39:01 +02:00
def test_parse_parent_and_child ( self ) :
prof = parse_profile_data ( ' profile /foo { \n profile /bar { \n } \n } \n ' . split ( ) , ' somefile ' , False , False )
self . assertEqual ( list ( prof . keys ( ) ) , [ ' /foo ' , ' /foo///bar ' ] )
self . assertEqual ( prof [ ' /foo ' ] [ ' parent ' ] , ' ' )
self . assertEqual ( prof [ ' /foo ' ] [ ' name ' ] , ' /foo ' )
self . assertEqual ( prof [ ' /foo ' ] [ ' filename ' ] , ' somefile ' )
self . assertEqual ( prof [ ' /foo ' ] [ ' flags ' ] , None )
self . assertEqual ( prof [ ' /foo///bar ' ] [ ' parent ' ] , ' /foo ' )
self . assertEqual ( prof [ ' /foo///bar ' ] [ ' name ' ] , ' /bar ' )
self . assertEqual ( prof [ ' /foo///bar ' ] [ ' filename ' ] , ' somefile ' )
self . assertEqual ( prof [ ' /foo///bar ' ] [ ' flags ' ] , None )
2020-05-08 21:45:26 +02:00
def test_parse_duplicate_profile ( self ) :
2015-05-29 13:00:32 +02:00
with self . assertRaises ( AppArmorException ) :
# file contains two profiles with the same name
2021-02-22 22:22:25 +01:00
parse_profile_data ( ' profile /foo { \n } \n profile /foo { \n } \n ' . split ( ) , ' somefile ' , False , False )
2015-05-29 13:00:32 +02:00
2020-05-08 21:45:26 +02:00
def test_parse_duplicate_child_profile ( self ) :
with self . assertRaises ( AppArmorException ) :
# file contains two child profiles with the same name
2021-02-22 22:22:25 +01:00
parse_profile_data ( ' profile /foo { \n profile /bar { \n } \n profile /bar { \n } \n } \n ' . split ( ) , ' somefile ' , False , False )
2020-05-08 21:45:26 +02:00
def test_parse_duplicate_hat ( self ) :
with self . assertRaises ( AppArmorException ) :
# file contains two hats with the same name
2021-02-22 22:22:25 +01:00
parse_profile_data ( ' profile /foo { \n ^baz { \n } \n ^baz { \n } \n } \n ' . split ( ) , ' somefile ' , False , False )
2020-05-08 21:45:26 +02:00
2018-11-28 11:04:49 -08:00
def test_parse_xattrs_01 ( self ) :
2021-02-22 22:22:25 +01:00
prof = parse_profile_data ( ' /foo xattrs=(user.bar=bar) { \n } \n ' . split ( ) , ' somefile ' , False , False )
2018-11-28 11:04:49 -08:00
self . assertEqual ( list ( prof . keys ( ) ) , [ ' /foo ' ] )
2021-04-04 00:45:14 +02:00
self . assertEqual ( prof [ ' /foo ' ] [ ' name ' ] , ' /foo ' )
self . assertEqual ( prof [ ' /foo ' ] [ ' filename ' ] , ' somefile ' )
self . assertEqual ( prof [ ' /foo ' ] [ ' flags ' ] , None )
self . assertEqual ( prof [ ' /foo ' ] [ ' xattrs ' ] , ' user.bar=bar ' )
2018-11-28 11:04:49 -08:00
def test_parse_xattrs_02 ( self ) :
2021-02-22 22:22:25 +01:00
prof = parse_profile_data ( ' /foo xattrs=(user.bar=bar user.foo=*) { \n } \n ' . split ( ) , ' somefile ' , False , False )
2018-11-28 11:04:49 -08:00
self . assertEqual ( list ( prof . keys ( ) ) , [ ' /foo ' ] )
2021-04-04 00:45:14 +02:00
self . assertEqual ( prof [ ' /foo ' ] [ ' name ' ] , ' /foo ' )
self . assertEqual ( prof [ ' /foo ' ] [ ' filename ' ] , ' somefile ' )
self . assertEqual ( prof [ ' /foo ' ] [ ' flags ' ] , None )
self . assertEqual ( prof [ ' /foo ' ] [ ' xattrs ' ] , ' user.bar=bar user.foo=* ' )
2018-11-28 11:04:49 -08:00
def test_parse_xattrs_03 ( self ) :
d = ' /foo xattrs=(user.bar=bar) flags=(complain) { \n } \n '
2021-02-22 22:22:25 +01:00
prof = parse_profile_data ( d . split ( ) , ' somefile ' , False , False )
2018-11-28 11:04:49 -08:00
self . assertEqual ( list ( prof . keys ( ) ) , [ ' /foo ' ] )
2021-04-04 00:45:14 +02:00
self . assertEqual ( prof [ ' /foo ' ] [ ' name ' ] , ' /foo ' )
self . assertEqual ( prof [ ' /foo ' ] [ ' filename ' ] , ' somefile ' )
self . assertEqual ( prof [ ' /foo ' ] [ ' flags ' ] , ' complain ' )
self . assertEqual ( prof [ ' /foo ' ] [ ' xattrs ' ] , ' user.bar=bar ' )
2018-11-28 11:04:49 -08:00
def test_parse_xattrs_04 ( self ) :
with self . assertRaises ( AppArmorException ) :
# flags before xattrs
d = ' /foo flags=(complain) xattrs=(user.bar=bar) { \n } \n '
2021-02-22 22:22:25 +01:00
parse_profile_data ( d . split ( ) , ' somefile ' , False , False )
2018-11-28 11:04:49 -08:00
2022-08-07 12:26:24 -04:00
2016-10-01 20:03:44 +02:00
class AaTest_get_file_perms_1 ( AATest ) :
2022-06-18 14:30:49 -04:00
tests = (
2022-08-07 12:26:24 -04:00
( ' /usr/share/common-licenses/foo/bar ' , { ' allow ' : { ' all ' : set ( ) , ' owner ' : { ' w ' } } , ' deny ' : { ' all ' : set ( ) , ' owner ' : set ( ) } , ' paths ' : { ' /usr/share/common-licenses/** ' } } ) ,
( ' /dev/null ' , { ' allow ' : { ' all ' : { ' r ' , ' w ' , ' k ' } , ' owner ' : set ( ) } , ' deny ' : { ' all ' : set ( ) , ' owner ' : set ( ) } , ' paths ' : { ' /dev/null ' } } ) ,
( ' /foo/bar ' , { ' allow ' : { ' all ' : { ' r ' , ' w ' } , ' owner ' : set ( ) } , ' deny ' : { ' all ' : set ( ) , ' owner ' : set ( ) } , ' paths ' : { ' /foo/bar ' } } ) , # exec perms not included
( ' /no/thing ' , { ' allow ' : { ' all ' : set ( ) , ' owner ' : set ( ) } , ' deny ' : { ' all ' : set ( ) , ' owner ' : set ( ) } , ' paths ' : set ( ) } ) ,
( ' /usr/lib/ispell/ ' , { ' allow ' : { ' all ' : set ( ) , ' owner ' : set ( ) } , ' deny ' : { ' all ' : set ( ) , ' owner ' : set ( ) } , ' paths ' : set ( ) } ) ,
( ' /usr/lib/aspell/*.so ' , { ' allow ' : { ' all ' : set ( ) , ' owner ' : set ( ) } , ' deny ' : { ' all ' : set ( ) , ' owner ' : set ( ) } , ' paths ' : set ( ) } ) ,
2022-06-18 14:30:49 -04:00
)
2016-10-01 20:03:44 +02:00
def _run_test ( self , params , expected ) :
self . createTmpdir ( )
2022-08-07 12:26:24 -04:00
# copy the local profiles to the test directory
2023-02-19 16:26:14 -05:00
self . profile_dir = self . tmpdir + ' /profiles '
2016-10-01 20:03:44 +02:00
shutil . copytree ( ' ../../profiles/apparmor.d/ ' , self . profile_dir , symlinks = True )
2017-07-11 13:30:29 +02:00
profile = apparmor . aa . ProfileStorage ( ' /test ' , ' /test ' , ' test-aa.py ' )
2016-10-01 20:03:44 +02:00
# simple profile without any includes
2022-09-10 19:45:22 -04:00
profile [ ' file ' ] . add ( FileRule . create_instance ( ' owner /usr/share/common-licenses/** w, ' ) )
profile [ ' file ' ] . add ( FileRule . create_instance ( ' /dev/null rwk, ' ) )
profile [ ' file ' ] . add ( FileRule . create_instance ( ' /foo/bar rwix, ' ) )
2016-10-01 20:03:44 +02:00
perms = get_file_perms ( profile , params , False , False ) # only testing with audit and deny = False
self . assertEqual ( perms , expected )
2022-08-07 12:26:24 -04:00
2016-10-01 20:03:44 +02:00
class AaTest_get_file_perms_2 ( AATest ) :
2022-06-18 14:30:49 -04:00
tests = (
2022-08-07 12:26:24 -04:00
( ' /usr/share/common-licenses/foo/bar ' , { ' allow ' : { ' all ' : { ' r ' } , ' owner ' : { ' w ' } } , ' deny ' : { ' all ' : set ( ) , ' owner ' : set ( ) } , ' paths ' : { ' /usr/share/common-licenses/** ' } } ) ,
( ' /usr/share/common-licenses/what/ever ' , { ' allow ' : { ' all ' : { ' r ' } , ' owner ' : { ' w ' } } , ' deny ' : { ' all ' : set ( ) , ' owner ' : set ( ) } , ' paths ' : { ' /usr/share/common-licenses/** ' , ' /usr/share/common-licenses/what/ever ' } } ) ,
( ' /dev/null ' , { ' allow ' : { ' all ' : { ' r ' , ' w ' , ' k ' } , ' owner ' : set ( ) } , ' deny ' : { ' all ' : set ( ) , ' owner ' : set ( ) } , ' paths ' : { ' /dev/null ' } } ) ,
( ' /foo/bar ' , { ' allow ' : { ' all ' : { ' r ' , ' w ' } , ' owner ' : set ( ) } , ' deny ' : { ' all ' : set ( ) , ' owner ' : set ( ) } , ' paths ' : { ' /foo/bar ' } } ) , # exec perms not included
( ' /no/thing ' , { ' allow ' : { ' all ' : set ( ) , ' owner ' : set ( ) } , ' deny ' : { ' all ' : set ( ) , ' owner ' : set ( ) } , ' paths ' : set ( ) } ) ,
( ' /usr/lib/ispell/ ' , { ' allow ' : { ' all ' : { ' r ' } , ' owner ' : set ( ) } , ' deny ' : { ' all ' : set ( ) , ' owner ' : set ( ) } , ' paths ' : { ' /usr/lib/ispell/ ' , ' / { usr/,}lib { ,32,64}/** ' } } ) , # from abstractions/enchant
( ' /usr/lib/aspell/*.so ' , { ' allow ' : { ' all ' : { ' m ' , ' r ' } , ' owner ' : set ( ) } , ' deny ' : { ' all ' : set ( ) , ' owner ' : set ( ) } , ' paths ' : { ' /usr/lib/aspell/* ' , ' /usr/lib/aspell/*.so ' , ' / { usr/,}lib { ,32,64}/** ' , ' / { usr/,}lib { ,32,64}/**.so* ' } } ) , # from abstractions/aspell via abstractions/enchant and from abstractions/base
2022-06-18 14:30:49 -04:00
)
2016-10-01 20:03:44 +02:00
def _run_test ( self , params , expected ) :
self . createTmpdir ( )
2022-08-07 12:26:24 -04:00
# copy the local profiles to the test directory
2023-02-19 16:26:14 -05:00
self . profile_dir = self . tmpdir + ' /profiles '
2016-10-01 20:03:44 +02:00
shutil . copytree ( ' ../../profiles/apparmor.d/ ' , self . profile_dir , symlinks = True )
# load the abstractions we need in the test
2020-06-01 15:54:34 +02:00
apparmor . aa . profile_dir = self . profile_dir
2020-06-01 17:03:52 +02:00
apparmor . aa . load_include ( os . path . join ( self . profile_dir , ' abstractions/base ' ) )
apparmor . aa . load_include ( os . path . join ( self . profile_dir , ' abstractions/bash ' ) )
apparmor . aa . load_include ( os . path . join ( self . profile_dir , ' abstractions/enchant ' ) )
apparmor . aa . load_include ( os . path . join ( self . profile_dir , ' abstractions/aspell ' ) )
2016-10-01 20:03:44 +02:00
2017-07-11 13:30:29 +02:00
profile = apparmor . aa . ProfileStorage ( ' /test ' , ' /test ' , ' test-aa.py ' )
2022-09-10 19:45:22 -04:00
profile [ ' inc_ie ' ] . add ( IncludeRule . create_instance ( ' include <abstractions/base> ' ) )
profile [ ' inc_ie ' ] . add ( IncludeRule . create_instance ( ' include <abstractions/bash> ' ) )
profile [ ' inc_ie ' ] . add ( IncludeRule . create_instance ( ' include <abstractions/enchant> ' ) )
2016-10-01 20:03:44 +02:00
2022-09-10 19:45:22 -04:00
profile [ ' file ' ] . add ( FileRule . create_instance ( ' owner /usr/share/common-licenses/** w, ' ) )
profile [ ' file ' ] . add ( FileRule . create_instance ( ' owner /usr/share/common-licenses/what/ever a, ' ) ) # covered by the above 'w' rule, so 'a' should be ignored
profile [ ' file ' ] . add ( FileRule . create_instance ( ' /dev/null rwk, ' ) )
profile [ ' file ' ] . add ( FileRule . create_instance ( ' /foo/bar rwix, ' ) )
2016-10-01 20:03:44 +02:00
perms = get_file_perms ( profile , params , False , False ) # only testing with audit and deny = False
self . assertEqual ( perms , expected )
2022-08-07 12:26:24 -04:00
2016-10-01 20:04:42 +02:00
class AaTest_propose_file_rules ( AATest ) :
2022-06-18 14:30:49 -04:00
tests = (
2022-08-07 12:26:24 -04:00
# log event path and perms expected proposals
( ( ' /usr/share/common-licenses/foo/bar ' , ' w ' ) , [ ' /usr/share/common*/foo/* rw, ' , ' /usr/share/common-licenses/** rw, ' , ' /usr/share/common-licenses/foo/bar rw, ' ] ) ,
( ( ' /dev/null ' , ' wk ' ) , [ ' /dev/null rwk, ' ] ) ,
( ( ' /foo/bar ' , ' rw ' ) , [ ' /foo/bar rw, ' ] ) ,
( ( ' /usr/lib/ispell/ ' , ' w ' ) , [ ' / { usr/,}lib { ,32,64}/** rw, ' , ' /usr/lib/ispell/ rw, ' ] ) ,
( ( ' /usr/lib/aspell/some.so ' , ' k ' ) , [ ' /usr/lib/aspell/* mrk, ' , ' /usr/lib/aspell/*.so mrk, ' , ' / { usr/,}lib { ,32,64}/** mrk, ' , ' / { usr/,}lib { ,32,64}/**.so* mrk, ' , ' /usr/lib/aspell/some.so mrk, ' ] ) ,
( ( ' /foo/log ' , ' w ' ) , [ ' /foo/log w, ' ] ) ,
2022-06-18 14:30:49 -04:00
)
2016-10-01 20:04:42 +02:00
def _run_test ( self , params , expected ) :
self . createTmpdir ( )
2022-08-07 12:26:24 -04:00
# copy the local profiles to the test directory
2023-02-19 16:26:14 -05:00
self . profile_dir = self . tmpdir + ' /profiles '
2016-10-01 20:04:42 +02:00
shutil . copytree ( ' ../../profiles/apparmor.d/ ' , self . profile_dir , symlinks = True )
# load the abstractions we need in the test
2020-06-01 15:54:34 +02:00
apparmor . aa . profile_dir = self . profile_dir
2020-06-01 17:03:52 +02:00
apparmor . aa . load_include ( os . path . join ( self . profile_dir , ' abstractions/base ' ) )
apparmor . aa . load_include ( os . path . join ( self . profile_dir , ' abstractions/bash ' ) )
apparmor . aa . load_include ( os . path . join ( self . profile_dir , ' abstractions/enchant ' ) )
apparmor . aa . load_include ( os . path . join ( self . profile_dir , ' abstractions/aspell ' ) )
2016-10-01 20:04:42 +02:00
# add some user_globs ('(N)ew') to simulate a professional aa-logprof user (and to make sure that part of the code also gets tested)
apparmor . aa . user_globs [ ' /usr/share/common*/foo/* ' ] = AARE ( ' /usr/share/common*/foo/* ' , True )
apparmor . aa . user_globs [ ' /no/thi*ng ' ] = AARE ( ' /no/thi*ng ' , True )
2017-07-11 13:30:29 +02:00
profile = apparmor . aa . ProfileStorage ( ' /test ' , ' /test ' , ' test-aa.py ' )
2022-09-10 19:45:22 -04:00
profile [ ' inc_ie ' ] . add ( IncludeRule . create_instance ( ' include <abstractions/base> ' ) )
profile [ ' inc_ie ' ] . add ( IncludeRule . create_instance ( ' include <abstractions/bash> ' ) )
profile [ ' inc_ie ' ] . add ( IncludeRule . create_instance ( ' include <abstractions/enchant> ' ) )
2020-05-13 21:45:00 +02:00
2022-09-10 19:45:22 -04:00
profile [ ' file ' ] . add ( FileRule . create_instance ( ' owner /usr/share/common-licenses/** w, ' ) )
profile [ ' file ' ] . add ( FileRule . create_instance ( ' /dev/null rwk, ' ) )
profile [ ' file ' ] . add ( FileRule . create_instance ( ' /foo/bar rwix, ' ) )
profile [ ' file ' ] . add ( FileRule . create_instance ( ' /foo/log a, ' ) ) # will be replaced with '/foo/log w,' (not 'wa')
2016-10-01 20:04:42 +02:00
rule_obj = FileRule ( params [ 0 ] , params [ 1 ] , None , FileRule . ALL , owner = False , log_event = True )
proposals = propose_file_rules ( profile , rule_obj )
self . assertEqual ( proposals , expected )
2014-11-27 23:20:26 +01:00
2017-12-18 19:37:35 +00:00
class AaTest_propose_file_rules_with_absolute_includes ( AATest ) :
2022-06-18 14:30:49 -04:00
tests = (
2022-08-07 12:26:24 -04:00
# log event path and perms expected proposals
( ( ' /not/found/anywhere ' , ' r ' ) , [ ' /not/found/anywhere r, ' ] ) ,
( ( ' /dev/null ' , ' w ' ) , [ ' /dev/null rw, ' ] ) ,
( ( ' /some/random/include ' , ' r ' ) , [ ' /some/random/include rw, ' ] ) ,
( ( ' /some/other/include ' , ' w ' ) , [ ' /some/other/* rw, ' , ' /some/other/inc* rw, ' , ' /some/other/include rw, ' ] ) ,
2022-06-18 14:30:49 -04:00
)
2017-12-18 19:37:35 +00:00
def _run_test ( self , params , expected ) :
self . createTmpdir ( )
2022-08-07 12:26:24 -04:00
# copy the local profiles to the test directory
2023-02-19 16:26:14 -05:00
self . profile_dir = self . tmpdir + ' /profiles '
2017-12-18 19:37:35 +00:00
shutil . copytree ( ' ../../profiles/apparmor.d/ ' , self . profile_dir , symlinks = True )
# load the abstractions we need in the test
2020-06-01 15:54:34 +02:00
apparmor . aa . profile_dir = self . profile_dir
2020-06-01 17:03:52 +02:00
apparmor . aa . load_include ( os . path . join ( self . profile_dir , ' abstractions/base ' ) )
2017-12-18 19:37:35 +00:00
abs_include1 = write_file ( self . tmpdir , ' test-abs1 ' , " /some/random/include rw, " )
apparmor . aa . load_include ( abs_include1 )
abs_include2 = write_file ( self . tmpdir , ' test-abs2 ' , " /some/other/* rw, " )
apparmor . aa . load_include ( abs_include2 )
abs_include3 = write_file ( self . tmpdir , ' test-abs3 ' , " /some/other/inc* rw, " )
apparmor . aa . load_include ( abs_include3 )
profile = apparmor . aa . ProfileStorage ( ' /test ' , ' /test ' , ' test-aa.py ' )
2022-09-10 19:45:22 -04:00
profile [ ' inc_ie ' ] . add ( IncludeRule . create_instance ( ' include <abstractions/base> ' ) )
2023-02-19 16:26:14 -05:00
profile [ ' inc_ie ' ] . add ( IncludeRule . create_instance ( ' include " {} " ' . format ( abs_include1 ) ) )
profile [ ' inc_ie ' ] . add ( IncludeRule . create_instance ( ' include " {} " ' . format ( abs_include2 ) ) )
profile [ ' inc_ie ' ] . add ( IncludeRule . create_instance ( ' include " {} " ' . format ( abs_include3 ) ) )
2017-12-18 19:37:35 +00:00
rule_obj = FileRule ( params [ 0 ] , params [ 1 ] , None , FileRule . ALL , owner = False , log_event = True )
proposals = propose_file_rules ( profile , rule_obj )
self . assertEqual ( proposals , expected )
class AaTest_nonexistent_includes ( AATest ) :
2022-06-18 14:30:49 -04:00
tests = (
2022-08-07 12:26:24 -04:00
( " /nonexistent/absolute/path " , AppArmorException ) ,
( " nonexistent/relative/path " , AppArmorBug ) , # load_include() only accepts absolute paths
2022-06-18 14:30:49 -04:00
)
2020-06-01 17:06:45 +02:00
def _run_test ( self , params , expected ) :
with self . assertRaises ( expected ) :
apparmor . aa . load_include ( params )
2017-12-18 19:37:35 +00:00
2022-08-07 12:26:24 -04:00
2021-04-02 19:35:59 +02:00
class AaTest_merged_to_split ( AATest ) :
2022-06-18 14:30:49 -04:00
tests = (
2022-08-07 12:26:24 -04:00
( " foo " , ( " foo " , " foo " ) ) ,
( " foo//bar " , ( " foo " , " bar " ) ) ,
( " foo//bar//baz " , ( " foo " , " bar " ) ) , # XXX known limitation
2022-06-18 14:30:49 -04:00
)
2021-04-02 19:35:59 +02:00
def _run_test ( self , params , expected ) :
merged = { }
merged [ params ] = True # simplified, but enough for this test
result = merged_to_split ( merged )
profile , hat = expected
self . assertEqual ( list ( result . keys ( ) ) , [ profile ] )
self . assertEqual ( list ( result [ profile ] . keys ( ) ) , [ hat ] )
self . assertTrue ( result [ profile ] [ hat ] )
2017-12-18 19:37:35 +00:00
2022-08-07 12:26:24 -04:00
2017-03-02 21:21:53 +00:00
setup_aa ( apparmor . aa )
2015-04-22 22:01:34 +02:00
setup_all_loops ( __name__ )
2014-11-27 23:20:26 +01:00
if __name__ == ' __main__ ' :
2018-04-08 20:18:30 +02:00
unittest . main ( verbosity = 1 )