From 4ecd6d00a5a4cf7e824e234de6c6da14d4d65c85 Mon Sep 17 00:00:00 2001 From: Chris PeBenito Date: Mon, 16 Mar 2015 10:46:33 -0400 Subject: [PATCH] Implement TypeAttributeQuery. closes #13 closes #14 --- seinfo | 11 ++- setools/__init__.py | 1 + setools/typeattrquery.py | 101 +++++++++++++++++++++++ tests/__init__.py | 1 + tests/typeattrquery.conf | 169 +++++++++++++++++++++++++++++++++++++++ tests/typeattrquery.py | 73 +++++++++++++++++ 6 files changed, 354 insertions(+), 2 deletions(-) create mode 100644 setools/typeattrquery.py create mode 100644 tests/typeattrquery.conf create mode 100644 tests/typeattrquery.py diff --git a/seinfo b/seinfo index 163086a..e2917dc 100755 --- a/seinfo +++ b/seinfo @@ -33,7 +33,7 @@ parser.add_argument("--flat", help="Print without item count nor indentation.", parser.add_argument("--debug", action="store_true", dest="debug", help="Enable debugging.") queries = parser.add_argument_group("Component Queries") -queries.add_argument("-a", "--attribute", help="Print type attributes.", dest="attrquery", +queries.add_argument("-a", "--attribute", help="Print type attributes.", dest="typeattrquery", default=None, nargs='?', const=True, metavar="ATTR") queries.add_argument("-b", "--bool", help="Print Booleans.", dest="boolquery", default=None, nargs='?', const=True, metavar="BOOL") @@ -198,6 +198,13 @@ try: q = setools.typequery.TypeQuery(p) components.append(("Types", q)) + if args.typeattrquery or args.all: + if isinstance(args.typeattrquery, str): + q = setools.typeattrquery.TypeAttributeQuery(p, name=args.typeattrquery) + else: + q = setools.typeattrquery.TypeAttributeQuery(p) + components.append(("Type Attributes", q)) + if args.userquery or args.all: if isinstance(args.userquery, str): q = setools.userquery.UserQuery(p, name=args.userquery) @@ -225,7 +232,7 @@ try: print(" Sensitivities: {0:7} Categories: {1:7}".format( p.level_count, p.category_count)) print(" Types: {0:7} Attributes: {1:7}".format( - p.type_count, p.attribute_count)) + p.type_count, p.type_attribute_count)) print(" Users: {0:7} Roles: {1:7}".format( p.user_count, p.role_count)) print(" Booleans: {0:7} Cond. Expr.: {1:7}".format( diff --git a/setools/__init__.py b/setools/__init__.py index 79dd9d6..6caee6d 100644 --- a/setools/__init__.py +++ b/setools/__init__.py @@ -36,6 +36,7 @@ from . import polcapquery from . import rolequery from . import sensitivityquery from . import typequery +from . import typeattrquery from . import userquery # Rule Queries diff --git a/setools/typeattrquery.py b/setools/typeattrquery.py new file mode 100644 index 0000000..941d81d --- /dev/null +++ b/setools/typeattrquery.py @@ -0,0 +1,101 @@ +# Copyright 2014-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 Lesser General Public License as +# published by the Free Software Foundation, either version 2.1 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 Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with SETools. If not, see +# . +# +import re + +from . import compquery + + +class TypeAttributeQuery(compquery.ComponentQuery): + + """Query SELinux policy type attributes.""" + + def __init__(self, policy, + name="", name_regex=False, + types=set(), types_equal=False, types_regex=False): + """ + Parameter: + policy The policy to query. + name The type name to match. + name_regex If true, regular expression matching + will be used on the type names. + types The type to match. + types_equal If true, only attributes with type sets + that are equal to the criteria will + match. Otherwise, any intersection + will match. + types_regex If true, regular expression matching + will be used on the type names instead + of set logic. + """ + + self.policy = policy + self.set_name(name, regex=name_regex) + self.set_types(types, regex=types_regex, equal=types_equal) + + def results(self): + """Generator which yields all matching types.""" + + for a in self.policy.typeattributes(): + if self.name and not self._match_name(a): + continue + + if self.types and not self._match_regex_or_set( + set(a.expand()), + self.types_cmp, + self.types_equal, + self.types_regex): + continue + + yield a + + def set_types(self, types, **opts): + """ + Set the criteria for the attribute's types. + + Parameter: + alias Name to match the component's types. + + Keyword Options: + regex If true, regular expression matching will be used + instead of set logic. + equal If true, the type set of the attribute + must equal the type criteria to + match. If false, any intersection in the + critera will cause a rule match. + + Exceptions: + NameError Invalid keyword option. + """ + + self.types = types + + for k in list(opts.keys()): + if k == "regex": + self.types_regex = opts[k] + elif k == "equal": + self.types_equal = opts[k] + else: + raise NameError("Invalid types option: {0}".format(k)) + + if not self.types: + self.types_cmp = None + elif self.types_regex: + self.types_cmp = re.compile(self.types) + else: + self.types_cmp = set(self.policy.lookup_type(t) for t in self.types) diff --git a/tests/__init__.py b/tests/__init__.py index 335d5a7..bf978f4 100644 --- a/tests/__init__.py +++ b/tests/__init__.py @@ -34,5 +34,6 @@ from . import rbacrulequery from . import rolequery from . import sensitivityquery from . import terulequery +from . import typeattrquery from . import typequery from . import userquery diff --git a/tests/typeattrquery.conf b/tests/typeattrquery.conf new file mode 100644 index 0000000..2155858 --- /dev/null +++ b/tests/typeattrquery.conf @@ -0,0 +1,169 @@ +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 low_s; +sensitivity medium_s alias med; +sensitivity high_s; + +dominance { low_s med high_s } + +category here; +category there; +category elsewhere alias lost; + +#level decl +level low_s:here.there; +level med:here, elsewhere; +level high_s:here.lost; + +#some constraints +mlsconstrain infoflow hi_r ((l1 dom l2) or (t1 == mls_exempt)); + +attribute mls_exempt; + +type system; +role system; +role system types system; + +################################################################################ +# Type enforcement declarations and rules + +######################################## +# +# Type Query +# + +# test 1 +# name: test1 +# types: unset +attribute test1; + +# test 2 +# name: test2(a|b) regex +# types: unset +attribute test2a; +attribute test2b; + +# test 10 +# name: unset +# types: +attribute test10a; +attribute test10b; +attribute test10c; +type test10t1, test10a; +type test10t2, test10a, test10b; +type test10t3, test10a, test10b, test10c; +type test10t4, test10b, test10c; +type test10t5, test10a, test10c; +type test10t6, test10b; +type test10t7, test10c; + +# test 11 +# name: unset +# types: +attribute test11a; +attribute test11b; +attribute test11c; +type test11t1, test11a; +type test11t2, test11a, test11b; +type test11t3, test11a, test11b, test11c; +type test11t4, test11b, test11c; +type test11t5, test11a, test11c; +type test11t6, test11b; +type test11t7, test11c; + +# test 12 +# name: unset +# types: +attribute test12a; +attribute test12b; +attribute test12c; +type test12t1, test12a; +type test12t2, test12a, test12b; +type test12t3, test12a, test12b, test12c; +type test12t4, test12b, test12c; +type test12t5, test12a, test12c; +type test12t6, test12b; +type test12t7, test12c; + +################################################################################ + +#users +user system roles system level med range low_s - high_s:here.lost; + +#normal constraints +constrain infoflow hi_w (u1 == u2); + +#isids +sid kernel system:system:system:medium_s:here +sid security system:system:system:high_s:lost + +#fs_use +fs_use_trans devpts system:object_r:system:low_s; +fs_use_xattr ext3 system:object_r:system:low_s; +fs_use_task pipefs system:object_r:system:low_s; + +#genfscon +genfscon proc / system:object_r:system:med +genfscon proc /sys system:object_r:system:low_s +genfscon selinuxfs / system:object_r:system:high_s:here.there + +portcon tcp 80 system:object_r:system:low_s + +netifcon eth0 system:object_r:system:low_s system:object_r:system:low_s + +nodecon 127.0.0.1 255.255.255.255 system:object_r:system:low_s:here +nodecon ::1 ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff system:object_r:system:low_s:here + diff --git a/tests/typeattrquery.py b/tests/typeattrquery.py new file mode 100644 index 0000000..ce98a9f --- /dev/null +++ b/tests/typeattrquery.py @@ -0,0 +1,73 @@ +# Copyright 2014-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 + +from setools import SELinuxPolicy +from setools.typeattrquery import TypeAttributeQuery + + +class TypeAttributeQueryTest(unittest.TestCase): + + def setUp(self): + self.p = SELinuxPolicy("tests/typeattrquery.conf") + + def test_000_unset(self): + """Type attribute query with no criteria.""" + # query with no parameters gets all attrs. + allattrs = sorted(self.p.typeattributes()) + + q = TypeAttributeQuery(self.p) + qattrs = sorted(q.results()) + + self.assertListEqual(allattrs, qattrs) + + def test_001_name_exact(self): + """Type attribute query with exact name match.""" + q = TypeAttributeQuery(self.p, name="test1") + + attrs = sorted(str(t) for t in q.results()) + self.assertListEqual(["test1"], attrs) + + def test_002_name_regex(self): + """Type attribute query with regex name match.""" + q = TypeAttributeQuery(self.p, name="test2(a|b)", name_regex=True) + + attrs = sorted(str(t) for t in q.results()) + self.assertListEqual(["test2a", "test2b"], attrs) + + def test_010_type_set_intersect(self): + """Type attribute query with type set intersection.""" + q = TypeAttributeQuery(self.p, types=["test10t1", "test10t7"]) + + attrs = sorted(str(t) for t in q.results()) + self.assertListEqual(["test10a", "test10c"], attrs) + + def test_011_type_set_equality(self): + """Type attribute query with type set equality.""" + q = TypeAttributeQuery(self.p, types=["test11t1", "test11t2", + "test11t3", "test11t5"], types_equal=True) + + attrs = sorted(str(t) for t in q.results()) + self.assertListEqual(["test11a"], attrs) + + def test_012_type_set_regex(self): + """Type attribute query with type set regex match.""" + q = TypeAttributeQuery(self.p, types="test12t(1|2)", types_regex=True) + + attrs = sorted(str(t) for t in q.results()) + self.assertListEqual(["test12a", "test12b"], attrs)