diff --git a/setools/policyrep/typeattr.py b/setools/policyrep/typeattr.py index c9da7d0..b4de786 100644 --- a/setools/policyrep/typeattr.py +++ b/setools/policyrep/typeattr.py @@ -146,5 +146,10 @@ class TypeAttribute(BaseType): """Generator that yields all aliases for this type.""" raise TypeError("{0} is an attribute, thus does not have aliases.".format(self)) + @property + def ispermissive(self): + """(T/F) the type is permissive.""" + raise TypeError("{0} is an attribute, thus cannot be permissive.".format(self)) + def statement(self): return "attribute {0};".format(self) diff --git a/tests/policyrep/__init__.py b/tests/policyrep/__init__.py index 1865bea..58017b9 100644 --- a/tests/policyrep/__init__.py +++ b/tests/policyrep/__init__.py @@ -18,4 +18,5 @@ from . import mls from . import role from . import selinuxpolicy +from . import typeattr from . import user diff --git a/tests/policyrep/typeattr.conf b/tests/policyrep/typeattr.conf new file mode 100644 index 0000000..94c1086 --- /dev/null +++ b/tests/policyrep/typeattr.conf @@ -0,0 +1,141 @@ +class infoflow +class infoflow2 +class infoflow3 +class infoflow4 +class infoflow5 +class infoflow6 +class infoflow7 + +sid kernel +sid security + +common infoflow +{ + low_w + med_w + hi_w + low_r + med_r + hi_r +} + +class infoflow +inherits infoflow + +class infoflow2 +inherits infoflow +{ + super_w + super_r +} + +class infoflow3 +{ + null +} + +class infoflow4 +inherits infoflow + +class infoflow5 +inherits infoflow + +class infoflow6 +inherits infoflow + +class infoflow7 +inherits infoflow +{ + super_w + super_r + super_none + super_both + super_unmapped +} + +sensitivity s0; +sensitivity s1; +sensitivity s2; + +dominance { s0 s1 s2 } + +category c0; +category c1; +category c2; +category c3; +category c4; +category c5; +category c6; +category c7; +category c8; +category c9; +category c10; +category c11; +category c12; +category c13; + +#level decl +level s0:c0.c2; +level s1:c0.c13; +level s2:c0.c13; + +#some constraints +mlsconstrain infoflow hi_r ((l1 dom l2) or (t1 == mls_exempt)); + +attribute mls_exempt; +attribute attr1; +attribute attr2; +attribute attr3; + +type system alias sysalias; +role system; +role system types system; + +role role20_r; +role role21a_r; +role role21b_r; +role role21c_r; + +role role20_r types system; +role role21a_r types system; +role role21b_r types system; +role role21c_r types system; + +type type30; +type type31a; +type type31b; +type type31c; +role system types { type30 type31a type31b type31c }; + +type everything alias { alias1 alias2 }, attr1, attr2; + +allow system self:infoflow hi_w; + +#users +user system roles { system role20_r role21a_r role21b_r role21c_r } level s0 range s0 - s2:c0.c4; +user user10 roles system level s0 range s0 - s2:c0.c4; +user user11a roles system level s0 range s0 - s2:c0.c4; +user user11b roles system level s0 range s0 - s2:c0.c4; +user user11c roles system level s0 range s0 - s2:c0.c4; + +#normal constraints +constrain infoflow hi_w (u1 == u2); + +#isids +sid kernel system:system:system:s0 +sid security system:system:system:s0 + +#fs_use +fs_use_trans devpts system:object_r:system:s0; +fs_use_xattr ext3 system:object_r:system:s0; +fs_use_task pipefs system:object_r:system:s0; + +#genfscon +genfscon proc / system:object_r:system:s1 +genfscon proc /sys system:object_r:system:s0 +genfscon selinuxfs / system:object_r:system:s2:c0.c4 +portcon tcp 1 system:system:system:s0:c0.c1 +netifcon eth0 system:object_r:system:s0 system:object_r:system:s0 +nodecon 127.0.0.1 255.255.255.255 system:object_r:system:s0 +nodecon ::1 ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff system:object_r:system:s0 + diff --git a/tests/policyrep/typeattr.py b/tests/policyrep/typeattr.py new file mode 100644 index 0000000..e1d5113 --- /dev/null +++ b/tests/policyrep/typeattr.py @@ -0,0 +1,240 @@ +# Copyright 2015, Tresys Technology, LLC +# +# This file is part of SETools. +# +# SETools is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 2 of the License, or +# (at your option) any later version. +# +# SETools 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. +# +# You should have received a copy of the GNU General Public License +# along with SETools. If not, see . +# +import unittest + +try: + from unittest.mock import Mock, patch +except ImportError: + from mock import Mock, patch + +from setools import SELinuxPolicy +from setools.policyrep import qpol +from setools.policyrep.exception import InvalidType +from setools.policyrep.typeattr import type_factory, type_or_attr_factory, attribute_factory + + +class TypeTest(unittest.TestCase): + + @classmethod + def setUpClass(cls): + cls.p = SELinuxPolicy("tests/policyrep/typeattr.conf") + + def mock_type_factory(self, name, attrs=[], alias=[], perm=False): + """Factory function for Type objects, using a mock qpol object.""" + mock_type = Mock(qpol.qpol_type_t) + mock_type.name.return_value = name + mock_type.type_iter.side_effect = AssertionError("Type iterator used") + mock_type.attr_iter.return_value = iter(attrs) + mock_type.alias_iter.return_value = iter(alias) + mock_type.ispermissive.return_value = perm + mock_type.isattr.return_value = False + mock_type.isalias.return_value = False + + return type_factory(self.p.policy, mock_type) + + def test_001_lookup(self): + """Type factory policy lookup.""" + type_ = type_factory(self.p.policy, "system") + self.assertEqual("system", type_.qpol_symbol.name(self.p.policy)) + + def test_002_lookup_invalid(self): + """Type factory policy invalid lookup.""" + with self.assertRaises(InvalidType): + type_factory(self.p.policy, "INVALID") + + def test_003_lookup_alias(self): + """Type factory policy lookup alias.""" + type_ = type_factory(self.p.policy, "sysalias", deref=True) + self.assertEqual("system", type_.qpol_symbol.name(self.p.policy)) + + def test_004_lookup_alias_no_deref(self): + """Type factory policy lookup alias (no dereference).""" + with self.assertRaises(TypeError): + type_ = type_factory(self.p.policy, "sysalias") + + def test_005_lookup_attr(self): + """Type factory policy lookup atribute.""" + with self.assertRaises(TypeError): + type_ = type_factory(self.p.policy, "attr1") + + def test_006_lookup2(self): + """Type factory policy lookup (type_or_attr_factory).""" + type_ = type_or_attr_factory(self.p.policy, "system") + self.assertEqual("system", type_.qpol_symbol.name(self.p.policy)) + + def test_007_lookup2_invalid(self): + """Type factory policy invalid lookup (type_or_attr_factory).""" + with self.assertRaises(InvalidType): + type_or_attr_factory(self.p.policy, "INVALID") + + def test_008_lookup2_alias(self): + """Type factory policy lookup alias (type_or_attr_factory).""" + type_ = type_or_attr_factory(self.p.policy, "sysalias", deref=True) + self.assertEqual("system", type_.qpol_symbol.name(self.p.policy)) + + def test_009_lookup2_alias_no_deref(self): + """Type factory policy lookup alias (no dereference, type_or_attr_factory).""" + with self.assertRaises(TypeError): + type_ = type_or_attr_factory(self.p.policy, "sysalias") + + def test_010_string(self): + """Type basic string rendering.""" + type_ = self.mock_type_factory("name10") + self.assertEqual("name10", str(type_)) + + def test_020_attrs(self): + """Type attributes""" + type_ = self.mock_type_factory("name20", attrs=['attr1', 'attr2', 'attr3']) + self.assertEqual(['attr1', 'attr2', 'attr3'], sorted(type_.attributes())) + + def test_030_aliases(self): + """Type aliases""" + type_ = self.mock_type_factory("name30", alias=['alias1', 'alias2', 'alias3']) + self.assertEqual(['alias1', 'alias2', 'alias3'], sorted(type_.aliases())) + + def test_040_expand(self): + """Type expansion""" + type_ = self.mock_type_factory("name40") + expanded = list(type_.expand()) + self.assertEqual(1, len(expanded)) + self.assertIs(type_, expanded[0]) + + def test_050_permissive(self): + """Type is permissive""" + type_ = self.mock_type_factory("name50a") + permtype = self.mock_type_factory("name50b", perm=True) + self.assertFalse(type_.ispermissive) + self.assertTrue(permtype.ispermissive) + + def test_060_statement(self): + """Type basic statement""" + type_ = self.mock_type_factory("name60") + self.assertEqual("type name60;", type_.statement()) + + def test_061_statement_one_attr(self): + """Type statement, one attribute""" + type_ = self.mock_type_factory("name61", attrs=['attr1']) + self.assertEqual("type name61, attr1;", type_.statement()) + + def test_062_statement_two_attr(self): + """Type statement, two attributes""" + type_ = self.mock_type_factory("name62", attrs=['attr1', 'attr2']) + self.assertEqual("type name62, attr1, attr2;", type_.statement()) + + def test_063_statement_one_alias(self): + """Type statement, one alias""" + type_ = self.mock_type_factory("name63", alias=['alias1']) + self.assertEqual("type name63 alias alias1;", type_.statement()) + + def test_064_statement_two_alias(self): + """Type statement, two aliases""" + type_ = self.mock_type_factory("name64", alias=['alias1', 'alias2']) + self.assertEqual("type name64 alias { alias1 alias2 };", type_.statement()) + + def test_065_statement_one_attr_one_alias(self): + """Type statement, one attribute, one alias""" + type_ = self.mock_type_factory("name65", attrs=['attr1'], alias=['alias1']) + self.assertEqual("type name65 alias alias1, attr1;", type_.statement()) + + def test_066_statement_two_attr_one_alias(self): + """Type statement, two attributes, one alias""" + type_ = self.mock_type_factory("name66", attrs=['attr1', 'attr2'], alias=['alias1']) + self.assertEqual("type name66 alias alias1, attr1, attr2;", type_.statement()) + + def test_067_statement_one_attr_two_alias(self): + """Type statement, one attribute, two aliases""" + type_ = self.mock_type_factory("name67", attrs=['attr2'], alias=['alias3', 'alias4']) + self.assertEqual("type name67 alias { alias3 alias4 }, attr2;", type_.statement()) + + def test_068_statement_two_attr_two_alias(self): + """Type statement, two attributes, two aliases""" + type_ = self.mock_type_factory("name68", attrs=['attr2', 'attr3'], + alias=['alias2', 'alias4']) + self.assertEqual("type name68 alias { alias2 alias4 }, attr2, attr3;", type_.statement()) + + +class TypeAttributeTest(unittest.TestCase): + + @classmethod + def setUpClass(cls): + cls.p = SELinuxPolicy("tests/policyrep/typeattr.conf") + + def mock_attr_factory(self, name, types=[]): + """Factory function for TypeAttribute objects, using a mock qpol object.""" + mock_type = Mock(qpol.qpol_type_t) + mock_type.name.return_value = name + mock_type.type_iter.return_value = iter(types) + mock_type.attr_iter.side_effect = AssertionError("Attr iter used") + mock_type.alias_iter.side_effect = AssertionError("Alias iter used") + mock_type.ispermissive.side_effect = AssertionError("Permissive used") + mock_type.isattr.return_value = True + mock_type.isalias.side_effect = AssertionError("Alias used") + + return attribute_factory(self.p.policy, mock_type) + + def test_001_lookup(self): + """TypeAttribute factory policy lookup.""" + attr = attribute_factory(self.p.policy, "attr1") + self.assertEqual("attr1", attr.qpol_symbol.name(self.p.policy)) + + def test_002_lookup_invalid(self): + """TypeAttribute factory policy invalid lookup.""" + with self.assertRaises(InvalidType): + attribute_factory(self.p.policy, "INVALID") + + def test_006_lookup2(self): + """TypeAttribute factory policy lookup (type_or_attr_factory).""" + attr = type_or_attr_factory(self.p.policy, "system") + self.assertEqual("system", attr.qpol_symbol.name(self.p.policy)) + + def test_007_lookup2_invalid(self): + """TypeAttribute factory policy invalid lookup (type_or_attr_factory).""" + with self.assertRaises(InvalidType): + type_or_attr_factory(self.p.policy, "INVALID") + + def test_010_string(self): + """TypeAttribute basic string rendering.""" + attr = self.mock_attr_factory("name10") + self.assertEqual("name10", str(attr)) + + def test_020_attrs(self): + """TypeAttribute attributes""" + attr = self.mock_attr_factory("name20") + with self.assertRaises(TypeError): + attr.attributes() + + def test_030_aliases(self): + """TypeAttribute aliases""" + attr = self.mock_attr_factory("name30") + with self.assertRaises(TypeError): + attr.aliases() + + def test_040_expand(self): + """TypeAttribute expansion""" + attr = self.mock_attr_factory("name40", types=['type31a', 'type31b', 'type31c']) + self.assertEqual(['type31a', 'type31b', 'type31c'], sorted(attr.expand())) + + def test_050_permissive(self): + with self.assertRaises(TypeError): + attr = self.mock_attr_factory("name20") + attr.ispermissive + + def test_060_statement(self): + """TypeAttribute basic statement""" + attr = self.mock_attr_factory("name60") + self.assertEqual("attribute name60;", attr.statement())