From 8c5a7caa9efa2a6916b1897fdf5a651e0ff8d6ba Mon Sep 17 00:00:00 2001 From: Chris PeBenito Date: Mon, 1 Feb 2016 09:06:02 -0500 Subject: [PATCH] Implement DefaultQuery Closes #93 Closes #74 --- setools/__init__.py | 3 + setools/defaultquery.py | 71 +++++++++++++++++++++++ tests/__init__.py | 1 + tests/defaultquery.conf | 125 ++++++++++++++++++++++++++++++++++++++++ tests/defaultquery.py | 98 +++++++++++++++++++++++++++++++ 5 files changed, 298 insertions(+) create mode 100644 setools/defaultquery.py create mode 100644 tests/defaultquery.conf create mode 100644 tests/defaultquery.py diff --git a/setools/__init__.py b/setools/__init__.py index 5e936e8..a726dfb 100644 --- a/setools/__init__.py +++ b/setools/__init__.py @@ -51,6 +51,9 @@ from .terulequery import TERuleQuery # Constraint queries from .constraintquery import ConstraintQuery +# Other queries +from .defaultquery import DefaultQuery + # In-policy Context Queries from .fsusequery import FSUseQuery from .genfsconquery import GenfsconQuery diff --git a/setools/defaultquery.py b/setools/defaultquery.py new file mode 100644 index 0000000..dac93bc --- /dev/null +++ b/setools/defaultquery.py @@ -0,0 +1,71 @@ +# 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 logging +import re + +from .query import PolicyQuery +from .descriptors import CriteriaDescriptor, CriteriaSetDescriptor +from .mixins import MatchObjClass + + +class DefaultQuery(MatchObjClass, PolicyQuery): + + """ + Query default_* statements. + + Parameter: + policy The policy to query. + + Keyword Parameters/Class attributes: + ruletype The rule type(s) to match. + tclass The object class(es) to match. + tclass_regex If true, use a regular expression for + matching the rule's object class. + default The default to base new contexts (e.g. "source" or "target") + default_range The range to use on new context, default_range only + ("low", "high", "low_high") + """ + + ruletype = CriteriaSetDescriptor(lookup_function="validate_default_ruletype") + default = CriteriaDescriptor(lookup_function="validate_default_value") + default_range = CriteriaDescriptor(lookup_function="validate_default_range") + + def results(self): + """Generator which yields all matching default_* statements.""" + self.log.info("Generating results from {0.policy}".format(self)) + self.log.debug("Ruletypes: {0.ruletype}".format(self)) + + for d in self.policy.defaults(): + if self.ruletype and d.ruletype not in self.ruletype: + continue + + if not self._match_object_class(d): + continue + + if self.default and d.default != self.default: + continue + + if self.default_range: + try: + if d.default_range != self.default_range: + continue + except AttributeError: + continue + + yield d diff --git a/tests/__init__.py b/tests/__init__.py index 75bffe7..a7600da 100644 --- a/tests/__init__.py +++ b/tests/__init__.py @@ -19,6 +19,7 @@ from . import boolquery from . import categoryquery from . import constraintquery from . import commonquery +from . import defaultquery from . import diff from . import dta from . import fsusequery diff --git a/tests/defaultquery.conf b/tests/defaultquery.conf new file mode 100644 index 0000000..772c167 --- /dev/null +++ b/tests/defaultquery.conf @@ -0,0 +1,125 @@ +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 +} + +######################################## +# +# Default settings +# + +default_user infoflow target; +default_role { infoflow infoflow3 } source; +default_type infoflow4 target; +default_range infoflow5 target low; +default_range infoflow7 target high; + +######################################### + +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 + + +################################################################################ + +#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/defaultquery.py b/tests/defaultquery.py new file mode 100644 index 0000000..f19f5ea --- /dev/null +++ b/tests/defaultquery.py @@ -0,0 +1,98 @@ +# Copyright 2016, 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, DefaultQuery +from setools.policyrep.exception import InvalidDefaultType, InvalidClass, \ + InvalidDefaultValue, InvalidDefaultRange + + +class DefaultQueryTest(unittest.TestCase): + + @classmethod + def setUpClass(cls): + cls.p = SELinuxPolicy("tests/defaultquery.conf") + + def test_000_unset(self): + """Default query: no criteria.""" + # query with no parameters gets all defaults + alldefaults = sorted(self.p.defaults()) + + q = DefaultQuery(self.p) + qdefaults = sorted(q.results()) + + self.assertListEqual(alldefaults, qdefaults) + + def test_001_ruletype(self): + """Default query: ruletype criterion.""" + q = DefaultQuery(self.p, ruletype=["default_user"]) + defaults = list(q.results()) + self.assertEqual(1, len(defaults)) + + d = defaults[0] + self.assertEqual("default_user", d.ruletype) + self.assertEqual("infoflow", d.tclass) + self.assertEqual("target", d.default) + + def test_010_class_list(self): + """Default query: object class list match.""" + q = DefaultQuery(self.p, tclass=["infoflow3", "infoflow4"]) + + defaults = sorted(d.tclass for d in q.results()) + self.assertListEqual(["infoflow3", "infoflow4"], defaults) + + def test_011_class_regex(self): + """Default query: object class regex match.""" + q = DefaultQuery(self.p, tclass="infoflow(3|5)", tclass_regex=True) + + defaults = sorted(c.tclass for c in q.results()) + self.assertListEqual(["infoflow3", "infoflow5"], defaults) + + def test_020_default(self): + """Default query: default setting.""" + q = DefaultQuery(self.p, default="source") + + defaults = sorted(c.tclass for c in q.results()) + self.assertListEqual(["infoflow", "infoflow3"], defaults) + + def test_030_default_range(self): + """Default query: default_range setting.""" + q = DefaultQuery(self.p, default_range="high") + + defaults = sorted(c.tclass for c in q.results()) + self.assertListEqual(["infoflow7"], defaults) + + def test_900_invalid_ruletype(self): + """Default query: invalid ruletype""" + with self.assertRaises(InvalidDefaultType): + q = DefaultQuery(self.p, ruletype=["INVALID"]) + + def test_901_invalid_class(self): + """Default query: invalid object class""" + with self.assertRaises(InvalidClass): + q = DefaultQuery(self.p, tclass=["INVALID"]) + + def test_902_invalid_default_value(self): + """Default query: invalid default value""" + with self.assertRaises(InvalidDefaultValue): + q = DefaultQuery(self.p, default="INVALID") + + def test_903_invalid_default_range(self): + """Default query: invalid default range""" + with self.assertRaises(InvalidDefaultRange): + q = DefaultQuery(self.p, default_range="INVALID")