#!/usr/bin/python3 # ---------------------------------------------------------------------- # Copyright (C) 2024 Canonical, Ltd. # Copyright (C) 2025 Christian Boltz # # This program is free software; you can redistribute it and/or # modify it under the terms of version 2 of the GNU General Public # License as published by the Free Software Foundation. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # ---------------------------------------------------------------------- import unittest from collections import namedtuple from common_test import AATest, setup_all_loops from apparmor.common import AppArmorException, AppArmorBug from apparmor.translations import init_translation from apparmor.rule.mount import MountRule, MountConditional _ = init_translation() class MountTestParse(AATest): tests = ( # Rule Operation Filesystem Options Source Destination Audit Deny Allow Comment ('mount -> **,', MountRule('mount', MountRule.ALL, MountRule.ALL, MountRule.ALL, '**', False, False, False, '')), ('mount options=(rw, shared) -> **,', MountRule('mount', MountRule.ALL, ('=', ('rw', 'shared')), MountRule.ALL, '**', False, False, False, '')), ('mount options=rw,', MountRule('mount', MountRule.ALL, ('=', ('rw')), MountRule.ALL, MountRule.ALL, False, False, False, '')), ('mount fstype=bpf options=rw bpf -> /sys/fs/bpf/,', MountRule('mount', ('=', ['bpf']), ('=', ('rw')), 'bpf', '/sys/fs/bpf/', False, False, False, '')), ('mount fstype=fuse.obex* options=rw bpf -> /sys/fs/bpf/,', MountRule('mount', ('=', ['fuse.obex*']), ('=', ('rw')), 'bpf', '/sys/fs/bpf/', False, False, False, '')), ('mount fstype=fuse.* options=rw bpf -> /sys/fs/bpf/,', MountRule('mount', ('=', ['fuse.*']), ('=', ('rw')), 'bpf', '/sys/fs/bpf/', False, False, False, '')), ('mount fstype=bpf options=(rw) random_label -> /sys/fs/bpf/,', MountRule('mount', ('=', ['bpf']), ('=', ('rw')), 'random_label', '/sys/fs/bpf/', False, False, False, '')), ('mount,', MountRule('mount', MountRule.ALL, MountRule.ALL, MountRule.ALL, MountRule.ALL, False, False, False, '')), ('mount fstype=(ext3, ext4),', MountRule('mount', ('=', ['ext3', 'ext4']), MountRule.ALL, MountRule.ALL, MountRule.ALL, False, False, False, '')), ('mount bpf,', MountRule('mount', MountRule.ALL, MountRule.ALL, 'bpf', MountRule.ALL, False, False, False, '')), ('mount none,', MountRule('mount', MountRule.ALL, MountRule.ALL, 'none', MountRule.ALL, False, False, False, '')), ('mount fstype=(procfs) none -> /foo,', MountRule('mount', ('=', ['procfs']), MountRule.ALL, 'none', '/foo', False, False, False, '')), ('mount fstype=(ext3, ext4) options=(ro),', MountRule('mount', ('=', ['ext3', 'ext4']), ('=', ('ro')), MountRule.ALL, MountRule.ALL, False, False, False, '')), ('mount @{mntpnt},', MountRule('mount', MountRule.ALL, MountRule.ALL, '@{mntpnt}', MountRule.ALL, False, False, False, '')), ('mount /a,', MountRule('mount', MountRule.ALL, MountRule.ALL, '/a', MountRule.ALL, False, False, False, '')), ('mount "/a space",', MountRule('mount', MountRule.ALL, MountRule.ALL, '/a space', MountRule.ALL, False, False, False, '')), ('mount fstype=(ext3, ext4) /a -> /b,', MountRule('mount', ('=', ['ext3', 'ext4']), MountRule.ALL, '/a', '/b', False, False, False, '')), ('mount fstype=(ext3, ext4) /a -> "/bar space",', MountRule('mount', ('=', ['ext3', 'ext4']), MountRule.ALL, '/a', '/bar space', False, False, False, '')), ('mount fstype=(ext3, ext4) options=(ro, sync) /a -> /b,', MountRule('mount', ('=', ['ext3', 'ext4']), ('=', ('ro', 'sync')), '/a', '/b', False, False, False, '')), ('mount fstype=(ext3, ext4) options=(ro, sync) /a -> /b, #cmt', MountRule('mount', ('=', ['ext3', 'ext4']), ('=', ('ro', 'sync')), '/a', '/b', False, False, False, ' #cmt')), ('mount fstype=({ext3,ext4}) options in (ro, sync) /a -> /b,', MountRule('mount', ('=', ['{ext3,ext4}']), ('in', ('ro', 'sync')), '/a', '/b', False, False, False, '')), ('mount fstype in (ext3, ext4) options=(ro, sync) /a -> /b, #cmt', MountRule('mount', ('in', ['ext3', 'ext4']), ('=', ('ro', 'sync')), '/a', '/b', False, False, False, ' #cmt')), ('mount fstype in (ext3, ext4) option in (ro, sync) /a, #cmt', MountRule('mount', ('in', ['ext3', 'ext4']), ('in', ('ro', 'sync')), '/a', MountRule.ALL, False, False, False, ' #cmt')), ('mount fstype=(ext3, ext4) option=(ro, sync) /a -> /b, #cmt', MountRule('mount', ('=', ['ext3', 'ext4']), ('=', ('ro', 'sync')), '/a', '/b', False, False, False, ' #cmt')), ('mount fstype=fuse.revokefs-fuse options=(nosuid,nodev,rw) revokefs-fuse -> /foo-*/**/,', MountRule('mount', ('=', ['fuse.revokefs-fuse']), ('=', ('nosuid', 'nodev', 'rw')), # noqa: E127 'revokefs-fuse', '/foo-*/**/', False, False, False, '')), # noqa: E127 ('mount options=(rw, rbind) {,/usr}/lib{,32,64,x32}/modules/ -> /tmp/snap.rootfs_*{,/usr}/lib/modules/,', MountRule('mount', MountRule.ALL, ('=', ('rw', 'rbind')), '{,/usr}/lib{,32,64,x32}/modules/', # noqa: E127 '/tmp/snap.rootfs_*{,/usr}/lib/modules/', # noqa: E127 False, False, False, '')), # noqa: E127 ('mount options=(runbindable, rw) -> /,', MountRule('mount', MountRule.ALL, ('=', ['runbindable', 'rw']), MountRule.ALL, '/', False, False, False, '')), ('mount "" -> /,', MountRule('mount', MountRule.ALL, MountRule.ALL, '', '/', False, False, False, '')), ('mount options=(ro) options=(rw) fstype=ext4 -> /dest,', MountRule('mount', ('=', ['ext4']), [('=', ('ro')), ('=', ('rw'))], # noqa: E127 MountRule.ALL, '/dest', False, False, False, '')), # noqa: E127 ('mount options=(ro) fstype=ext4 options=(rw) /src -> /dest,', MountRule('mount', ('=', ['ext4']), [('=', ('ro')), ('=', ('rw'))], # noqa: E127 '/src', '/dest', False, False, False, '')), # noqa: E127 ('mount options in (ro) options in (rw) fstype=ext4 -> /dest,', MountRule('mount', ('=', ['ext4']), [('in', ('ro')), ('in', ('rw'))], # noqa: E127 MountRule.ALL, '/dest', False, False, False, '')), # noqa: E127 ('mount options in (ro) fstype=ext4 options in (rw) -> /dest,', MountRule('mount', ('=', ['ext4']), [('in', ('ro')), ('in', ('rw'))], # noqa: E127 MountRule.ALL, '/dest', False, False, False, '')), # noqa: E127 ('mount options = (ro) options in (rw) fstype=ext4 -> /dest,', MountRule('mount', ('=', ['ext4']), [('=', ('ro')), ('in', ('rw'))], # noqa: E127 MountRule.ALL, '/dest', False, False, False, '')), # noqa: E127 ('mount options = (ro) fstype=ext4 options in (rw) -> /dest,', MountRule('mount', ('=', ['ext4']), [('=', ('ro')), ('in', ('rw'))], # noqa: E127 MountRule.ALL, '/dest', False, False, False, '')), # noqa: E127 ('mount options=(ro) fstype=ext3 fstype=ext4 -> /dest,', MountRule('mount', [('=', ['ext3']), ('=', ['ext4'])], ('=', ('ro')), MountRule.ALL, '/dest', False, False, False, '')), # noqa: E127 ('mount fstype=ext3 options=(ro) fstype=ext4 src -> /dest,', MountRule('mount', [('=', ['ext3']), ('=', ['ext4'])], ('=', ('ro')), 'src', '/dest', False, False, False, '')), # noqa: E127 ('mount options=(ro) fstype in (ext3) fstype in (ext4) -> /dest,', MountRule('mount', [('in', ['ext3']), ('in', ['ext4'])], ('=', ('ro')), MountRule.ALL, '/dest', False, False, False, '')), # noqa: E127 ('mount fstype in (ext3) options=(ro) fstype in (ext4) -> /dest,', MountRule('mount', [('in', ['ext3']), ('in', ['ext4'])], ('=', ('ro')), MountRule.ALL, '/dest', False, False, False, '')), # noqa: E127 ('mount options=(ro) fstype in (ext3) fstype=(ext4) -> /dest,', MountRule('mount', [('in', ['ext3']), ('=', ['ext4'])], ('=', ('ro')), MountRule.ALL, '/dest', False, False, False, '')), # noqa: E127 ('mount fstype = (ext3) options=(ro) fstype in ext4 -> /dest,', MountRule('mount', [('=', ['ext3']), ('in', ['ext4'])], ('=', ('ro')), MountRule.ALL, '/dest', False, False, False, '')), # noqa: E127 ('umount,', MountRule('umount', MountRule.ALL, MountRule.ALL, MountRule.ALL, MountRule.ALL, False, False, False, '')), ('umount fstype=ext3,', MountRule('umount', ('=', ['ext3']), MountRule.ALL, MountRule.ALL, MountRule.ALL, False, False, False, '')), ('umount /a,', MountRule('umount', MountRule.ALL, MountRule.ALL, MountRule.ALL, '/a', False, False, False, '')), ('remount,', MountRule('remount', MountRule.ALL, MountRule.ALL, MountRule.ALL, MountRule.ALL, False, False, False, '')), ('remount fstype=ext4,', MountRule('remount', ('=', ['ext4']), MountRule.ALL, MountRule.ALL, MountRule.ALL, False, False, False, '')), ('remount /b,', MountRule('remount', MountRule.ALL, MountRule.ALL, MountRule.ALL, '/b', False, False, False, '')), ) def _run_test(self, rawrule, expected): self.assertTrue(MountRule.match(rawrule)) obj = MountRule.create_instance(rawrule) expected.raw_rule = rawrule.strip() self.assertTrue(obj.is_equal(expected, True), f'\n {rawrule} expected,\n {obj.get_clean()} returned by obj.get_clean()\n {expected.get_clean()} returned by expected.get_clean()') def test_valid_mount_changing_propagation(self): # Rules changing propagation type can either specify a source or a dest (these are equivalent for apparmor_parser in this specific case) but not both. MountRule('mount', MountRule.ALL, ('=', ('runbindable')), '/foo', MountRule.ALL) MountRule('mount', MountRule.ALL, ('=', ('runbindable')), MountRule.ALL, '/foo') def test_valid_bind_mount(self): # Fstype must remain empty in bind rules MountRule('mount', MountRule.ALL, ('=', ('bind')), '/foo', MountRule.ALL) MountRule('mount', MountRule.ALL, ('=', ('bind')), MountRule.ALL, '/bar') MountRule('mount', MountRule.ALL, ('=', ('bind')), '/foo', '/bar') class MountTestParseInvalid(AATest): tests = ( # exception matches regex ('mount fstype=,', (AppArmorException, True)), ('mount fstype=(),', (AppArmorException, True)), ('mount options=(),', (AppArmorException, True)), ('mount option=(invalid),', (AppArmorException, True)), ('mount option=(ext3ext4),', (AppArmorException, True)), ('priority=-1042 umount,', (AppArmorException, True)), ('mount fstype=({unclosed_regex),', (AppArmorException, True)), # invalid AARE ('mount fstype=({closed}twice}),', (AppArmorException, True)), # invalid AARE ('foo,', (AppArmorException, False)), ('priority=a mount,', (AppArmorException, False)), ('priority=a umount,', (AppArmorException, False)), ('priority=a unmount,', (AppArmorException, False)), ('priority=a remount,', (AppArmorException, False)), ) def _run_test(self, rawrule, expected): self.parseInvalidRule(MountRule, rawrule, expected) class MountTestInvalid(AATest): def test_invalid_priority_1(self): with self.assertRaises(TypeError): MountRule('mount', MountRule.ALL, MountRule.ALL, MountRule.ALL, MountRule.ALL, priority=MountRule.ALL) def test_invalid_priority_2(self): with self.assertRaises(AppArmorException): MountRule('mount', MountRule.ALL, MountRule.ALL, MountRule.ALL, MountRule.ALL, priority='invalid') def test_diff_non_mountrule(self): exp = namedtuple('exp', ('audit', 'deny', 'priority')) obj = MountRule('mount', ('=', ['ext4']), MountRule.ALL, MountRule.ALL, MountRule.ALL) with self.assertRaises(AppArmorBug): obj.is_equal(exp(False, False, None), False) def test_diff_invalid_fstype_equals_or_in(self): with self.assertRaises(AppArmorBug): MountRule('mount', ('ext3', 'ext4'), MountRule.ALL, MountRule.ALL, MountRule.ALL) # fstype[0] should be '=' or 'in' def test_diff_invalid_fstype_aare_2(self): fslists = [ ['invalid_{_regex'], ['ext4', 'invalid_}_regex'], ['ext4', '{invalid} {regex}'] ] for fslist in fslists: with self.assertRaises(AppArmorException): MountRule('mount', ('=', fslist), MountRule.ALL, MountRule.ALL, MountRule.ALL) def test_diff_invalid_options_equals_or_in(self): with self.assertRaises(AppArmorBug): MountRule('mount', MountRule.ALL, ('rbind', 'rw'), MountRule.ALL, MountRule.ALL) # fstype[0] should be '=' or 'in' def test_diff_invalid_options_keyword(self): with self.assertRaises(AppArmorException): MountRule('mount', MountRule.ALL, ('=', 'invalid'), MountRule.ALL, MountRule.ALL) # fstype[0] should be '=' or 'in' def test_diff_fstype(self): obj1 = MountRule('mount', ('=', ['ext4']), MountRule.ALL, MountRule.ALL, MountRule.ALL) obj2 = MountRule('mount', MountRule.ALL, MountRule.ALL, MountRule.ALL, MountRule.ALL) self.assertFalse(obj1.is_equal(obj2, False)) def test_diff_source(self): obj1 = MountRule('mount', MountRule.ALL, MountRule.ALL, '/foo', MountRule.ALL) obj2 = MountRule('mount', MountRule.ALL, MountRule.ALL, '/bar', MountRule.ALL) self.assertFalse(obj1.is_equal(obj2, False)) def test_invalid_umount_with_source(self): with self.assertRaises(AppArmorException): MountRule('umount', MountRule.ALL, MountRule.ALL, '/foo', MountRule.ALL) # Umount and remount shall not have a source def test_invalid_remount_with_source(self): with self.assertRaises(AppArmorException): MountRule('remount', MountRule.ALL, MountRule.ALL, '/foo', MountRule.ALL) def test_invalid_mount_changing_propagation(self): # Rules changing propagation type can either specify a source or a dest (these are equivalent for apparmor_parser in this specific case) but not both. with self.assertRaises(AppArmorException): MountRule('mount', MountRule.ALL, ('=', ('runbindable')), '/foo', '/bar') # Rules changing propagation type cannot specify a fstype. with self.assertRaises(AppArmorException): MountRule('mount', ('=', ('ext4')), ('=', ('runbindable')), MountRule.ALL, '/foo') def test_invalid_bind_mount(self): # Bind mount rules cannot specify a fstype. with self.assertRaises(AppArmorException): MountRule('mount', ('=', ('ext4')), ('=', ('bind')), MountRule.ALL, '/foo') def test_invalid_cond_type(self): # cond_type cannot be None if all_values is False with self.assertRaises(AppArmorBug): obj = MountConditional('name', [], False, '=', cond_type=None) obj.is_covered(obj) class MountTestGlob(AATest): def test_glob(self): globList = [( 'mount options=(bind, rw) /home/user/Downloads/ -> /mnt/a/,', 'mount options=(bind, rw) /home/user/Downloads/,', 'mount options=(bind, rw) /home/user/*/,', 'mount options=(bind, rw) /home/**/,', 'mount options=(bind, rw),', 'mount,', 'mount,', )] for globs in globList: for i in range(len(globs) - 1): rule = MountRule.create_instance(globs[i]) rule.glob() self.assertEqual(rule.get_clean(), globs[i + 1]) class MountTestClean(AATest): tests = ( # raw rule clean rule (' mount , # foo ', 'mount, # foo'), (' mount fstype = ( sysfs ) , ', 'mount fstype=(sysfs),'), (' mount fstype = ( sysfs , procfs ) , ', 'mount fstype=(procfs, sysfs),'), (' mount options = ( rw ) , ', 'mount options=(rw),'), (' mount options = ( rw , noatime ) , ', 'mount options=(noatime, rw),'), (' mount fstype in ( sysfs ) , ', 'mount fstype in (sysfs),'), (' mount fstype in ( sysfs , procfs ) , ', 'mount fstype in (procfs, sysfs),'), (' mount options in ( rw ) , ', 'mount options in (rw),'), (' mount options in ( rw , noatime ) , ', 'mount options in (noatime, rw),'), (' mount none -> /foo , ', 'mount none -> /foo,'), (' mount "" -> /foo , ', 'mount "" -> /foo,'), (' mount "/f /b" -> "/foo bar" , ', 'mount "/f /b" -> "/foo bar",'), (' umount , ', 'umount,'), (' umount /foo , ', 'umount /foo,'), (' remount , ', 'remount,'), (' remount /foo , ', 'remount /foo,'), ('priority =1 mount "" -> /foo , ', 'priority=1 mount "" -> /foo,'), ('priority=0 audit mount "/f /b" -> "/foo bar" , ', 'priority=0 audit mount "/f /b" -> "/foo bar",'), (' priority = +10 umount , ', 'priority=10 umount,'), (' priority=-2 deny umount /foo , ', 'priority=-2 deny umount /foo,'), ('priority= 32 audit deny remount , ', 'priority=32 audit deny remount,'), (' priority = -32 remount /foo , ', 'priority=-32 remount /foo,'), ) def _run_test(self, rawrule, expected): self.assertTrue(MountRule.match(rawrule)) obj = MountRule.create_instance(rawrule) clean = obj.get_clean() raw = obj.get_raw() self.assertEqual(expected, clean, 'unexpected clean rule') self.assertEqual(rawrule.strip(), raw, 'unexpected raw rule') class MountLogprofHeaderTest(AATest): tests = ( ('mount,', [_('Operation'), _('mount'), _('Fstype'), _('ALL'), _('Options'), _('ALL'), _('Source'), _('ALL'), _('Destination'), _('ALL')]), ('mount options=(ro, nosuid) /a,', [_('Operation'), _('mount'), _('Fstype'), _('ALL'), _('Options'), ('=', _('nosuid ro')), _('Source'), _('/a'), _('Destination'), _('ALL')]), ('mount fstype=(ext3, ext4) options=(ro, nosuid) /a -> /b,', [_('Operation'), _('mount'), _('Fstype'), ('=', _('ext3 ext4')), _('Options'), ('=', _('nosuid ro')), _('Source'), _('/a'), _('Destination'), _('/b')]) ) def _run_test(self, params, expected): obj = MountRule.create_instance(params) self.assertEqual(obj.logprof_header(), expected) class MountIsCoveredTest(AATest): def test_is_covered(self): obj = MountRule('mount', ('=', ('ext3', 'ext4')), ('=', ('ro')), '/foo/b*', '/b*') tests = [ ('mount', ('=', ['ext3', 'ext4']), ('=', ('ro')), '/foo/b', '/bar'), ('mount', ('=', ['ext3', 'ext4']), ('=', ('ro')), '/foo/bar', '/b'), ('mount', ('=', ['ext3', 'ext4']), [('=', ('ro'))], '/foo/bar', '/b') ] for test in tests: self.assertTrue(obj.is_covered(MountRule(*test))) self.assertFalse(obj.is_equal(MountRule(*test))) def test_is_covered_fs_source(self): obj = MountRule('mount', ('=', ['ext3', 'ext4']), ('=', ('ro')), 'tmpfs', MountRule.ALL) self.assertTrue(obj.is_covered(MountRule('mount', ('=', ['ext3']), ('=', ('ro')), 'tmpfs', MountRule.ALL))) self.assertFalse(obj.is_equal(MountRule('mount', ('=', ['ext3']), ('=', ('ro')), 'tmpfs', MountRule.ALL))) def test_is_covered_aare_1(self): obj = MountRule('mount', ('=', ['sys*', 'fuse.*']), ('=', ('ro')), 'tmpfs', MountRule.ALL) tests = [ ('mount', ('=', ['sysfs', 'fuse.s3fs']), ('=', ('ro')), 'tmpfs', MountRule.ALL), ('mount', ('=', ['sysfs', 'fuse.jmtpfs', 'fuse.s3fs', 'fuse.obexfs', 'fuse.obexautofs', 'fuse.fuseiso']), ('=', ('ro')), 'tmpfs', MountRule.ALL) ] for test in tests: self.assertTrue(obj.is_covered(MountRule(*test))) self.assertFalse(obj.is_equal(MountRule(*test))) def test_is_covered_aare_2(self): obj = MountRule('mount', ('=', ['ext{3,4}', '{cgroup*,fuse.*}']), ('=', ('ro')), 'tmpfs', MountRule.ALL) tests = [ ('mount', ('=', ['ext3']), ('=', ('ro')), 'tmpfs', MountRule.ALL), ('mount', ('=', ['ext3', 'ext4', 'cgroup', 'cgroup2', 'fuse.jmtpfs', 'fuse.s3fs', 'fuse.obexfs', 'fuse.obexautofs', 'fuse.fuseiso']), ('=', ('ro')), 'tmpfs', MountRule.ALL) ] for test in tests: self.assertTrue(obj.is_covered(MountRule(*test))) self.assertFalse(obj.is_equal(MountRule(*test))) def test_is_covered_options_diff_operator(self): obj = MountRule('mount', ('=', ('ext3', 'ext4')), ('=', ('ro')), '/foo/b*', '/b*') test_obj = MountRule('mount', ('=', ('ext3', 'ext4')), ('in', ('ro')), '/foo/b*', '/b*') self.assertFalse(obj.is_covered(test_obj), '\n' + test_obj.get_clean() + '\n should not be covered by\n' + obj.get_clean()) def test_is_covered_options_all(self): obj = MountRule('mount', ('=', ('ext3', 'ext4')), MountRule.ALL, '/foo/b*', '/b*') test_obj = MountRule('mount', ('=', ('ext3', 'ext4')), ('in', ('ro')), '/foo/b*', '/b*') self.assertTrue(obj.is_covered(test_obj), '\n' + test_obj.get_clean() + '\n should be covered by\n' + obj.get_clean()) def test_is_covered_options_true(self): obj = MountRule('mount', ('=', ('ext3', 'ext4')), [('in', ('ro')), ('=', ('rw', 'noexec')), ('in', ('ro', 'nosuid'))], '/foo/b*', '/b*') test_obj = MountRule('mount', ('=', ('ext3', 'ext4')), [('=', ('rw', 'noexec')), ('in', ('ro', 'nosuid'))], '/foo/b*', '/b*') self.assertTrue(obj.is_covered(test_obj), '\n' + test_obj.get_clean() + '\n should be covered by\n' + obj.get_clean()) def test_is_equal_options_diff_operator(self): obj = MountRule('mount', ('=', ('ext3', 'ext4')), ('=', ('ro')), '/foo/b*', '/b*') test_obj = MountRule('mount', ('=', ('ext3', 'ext4')), ('in', ('ro')), '/foo/b*', '/b*') self.assertFalse(obj.is_equal(test_obj, True), '\n' + test_obj.get_clean() + '\n should not be equal to\n' + obj.get_clean()) def test_is_equal_options_diff_options(self): obj = MountRule('mount', ('=', ('ext3', 'ext4')), [('in', ('ro')), ('=', ('nosuid', 'noexec'))], '/foo/b*', '/b*') test_obj = MountRule('mount', ('=', ('ext3', 'ext4')), ('in', ('ro')), '/foo/b*', '/b*') self.assertFalse(obj.is_equal(test_obj, True), '\n' + test_obj.get_clean() + '\n should not be equal to\n' + obj.get_clean()) def test_is_equal_options_true(self): obj = MountRule('mount', ('=', ('ext3', 'ext4')), [('in', ('ro')), ('=', ('nosuid', 'noexec'))], '/foo/b*', '/b*') test_obj = MountRule('mount', ('=', ('ext3', 'ext4')), [('in', ('ro')), ('=', ('nosuid', 'noexec'))], '/foo/b*', '/b*') self.assertTrue(obj.is_equal(test_obj, True), '\n' + test_obj.get_clean() + '\n should be equal to\n' + obj.get_clean()) def test_eq_cond_diff_type(self): obj = MountConditional('options', ['ro'], False, 'in', 'aare') test_obj = MountConditional('options', ['ro'], False, 'in', 'list') self.assertFalse(test_obj == obj, 'cond_types should be different') def test_eq_cond_diff_instance(self): obj = MountRule('mount', ('=', ('ext3', 'ext4')), [('in', ('ro')), ('=', ('nosuid', 'noexec'))], '/foo/b*', '/b*') test_obj = MountConditional('options', ['ro'], False, 'in', 'list') self.assertFalse(test_obj == obj, 'Incompatible comparison') def test_covered_cond_diff_instance(self): obj = MountRule('mount', ('=', ('ext3', 'ext4')), [('in', ('ro')), ('=', ('nosuid', 'noexec'))], '/foo/b*', '/b*') test_obj = MountConditional('options', ['ro'], False, 'in', 'list') self.assertFalse(test_obj.is_covered(obj), 'Incompatible comparison') def test_covered_cond_diff_name(self): obj = MountConditional('foo', ['ro'], False, '=', 'list') test_obj = MountConditional('options', ['ro'], False, '=', 'list') self.assertFalse(test_obj.is_covered(obj), 'Incompatible comparison') def test_is_notcovered(self): obj = MountRule('mount', ('=', ['ext3', 'ext4']), ('=', ('ro')), '/foo/b*', '/b*') tests = [ ('mount', ('in', ['ext3', 'ext4']), ('=', ('ro')), '/foo/bar', '/bar'), ('mount', ('=', ['procfs', 'ext4']), ('=', ('ro')), '/foo/bar', '/bar'), ('mount', ('=', ['ext3']), ('=', ('rw')), '/foo/bar', '/bar'), ('mount', ('=', ['ext3', 'ext4']), MountRule.ALL, '/foo/b*', '/bar'), ('mount', MountRule.ALL, ('=', ('ro')), '/foo/b*', '/bar'), ('mount', ('=', ['ext3', 'ext4']), ('=', ('ro')), '/invalid/bar', '/bar'), ('umount', MountRule.ALL, MountRule.ALL, MountRule.ALL, '/bar'), ('remount', MountRule.ALL, MountRule.ALL, MountRule.ALL, '/bar'), ('mount', ('=', ['ext3', 'ext4']), ('=', ('ro')), 'tmpfs', '/bar'), ('mount', ('=', ['ext3', 'ext4']), ('=', ('ro')), '/foo/b*', '/invalid'), ('mount', ('=', ['ext3']), ('in', ('ro')), '/foo/bar', '/bar'), ('mount', ('=', ['ext3']), [('in', ('ro')), ('=', ('rw'))], '/foo/bar', '/bar'), ('mount', ('=', ['ext3']), [('=', ('ro')), ('in', ('rw'))], '/foo/bar', '/bar'), ('mount', ('=', ['ext3']), [('=', ('ro', 'nosuid')), ('in', ('rw'))], '/foo/bar', '/bar'), ] for test in tests: self.assertFalse(obj.is_covered(MountRule(*test))) self.assertFalse(obj.is_equal(MountRule(*test))) def test_is_not_covered_fs_source(self): obj = MountRule('mount', ('=', ['ext3', 'ext4']), ('=', ('ro')), 'tmpfs', MountRule.ALL) test = ('mount', ('=', ['ext3', 'ext4']), ('=', ('ro')), 'procfs', MountRule.ALL) self.assertFalse(obj.is_covered(MountRule(*test))) self.assertFalse(obj.is_equal(MountRule(*test))) def test_is_not_covered_fs_options(self): obj = MountRule('mount', MountRule.ALL, ('=', ('ro')), 'tmpfs', MountRule.ALL) test = ('mount', MountRule.ALL, ('=', ('rw')), 'procfs', MountRule.ALL) self.assertFalse(obj.is_covered(MountRule(*test))) self.assertFalse(obj.is_equal(MountRule(*test))) setup_all_loops(__name__) if __name__ == '__main__': unittest.main(verbosity=1)