From 349dcffc05968d6db0a338eab961da7c4d36692c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20G=C3=B6ttsche?= Date: Mon, 6 Jan 2025 17:33:05 +0100 Subject: [PATCH] Add option to see roles allowed for single type MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Closes: #140 Signed-off-by: Christian Göttsche --- seinfo | 8 ++ setools/__init__.py | 1 + setools/roletypesquery.py | 36 +++++++ tests/library/roletypesquery.conf | 144 +++++++++++++++++++++++++++ tests/library/test_roletypesquery.py | 38 +++++++ 5 files changed, 227 insertions(+) create mode 100644 setools/roletypesquery.py create mode 100644 tests/library/roletypesquery.conf create mode 100644 tests/library/test_roletypesquery.py diff --git a/seinfo b/seinfo index 80d308ce..99180c36 100755 --- a/seinfo +++ b/seinfo @@ -76,6 +76,8 @@ queries.add_argument("--polcap", help="Print policy capabilities.", dest="polcap nargs='?', const=True, metavar="NAME") queries.add_argument("--portcon", help="Print portcon statements.", dest="portconquery", nargs='?', const=True, metavar="PORTNUM[-PORTNUM]") +queries.add_argument("--role_types", help="Print all roles associated with the given type.", + dest="roletypesquery", nargs=1, metavar="TYPE") queries.add_argument("--sensitivity", help="Print MLS sensitivities.", dest="mlssensquery", nargs='?', const=True, metavar="SENS") queries.add_argument("--typebounds", help="Print typebounds statements.", dest="typeboundsquery", @@ -263,6 +265,12 @@ try: components.append(("Roles", rq, lambda x: x.statement())) + if args.roletypesquery: + q = setools.RoleTypesQuery(p) + q.name = args.roletypesquery[0] + + components.append(("Roles", q, lambda x: x.statement())) + if args.mlssensquery or args.all: msq = setools.SensitivityQuery(p, alias_deref=True) if isinstance(args.mlssensquery, str): diff --git a/setools/__init__.py b/setools/__init__.py index d7090a81..321440f7 100644 --- a/setools/__init__.py +++ b/setools/__init__.py @@ -44,6 +44,7 @@ from .objclassquery import ObjClassQuery from .polcapquery import PolCapQuery from .rolequery import RoleQuery +from .roletypesquery import RoleTypesQuery from .sensitivityquery import SensitivityQuery from .typequery import TypeQuery from .typeattrquery import TypeAttributeQuery diff --git a/setools/roletypesquery.py b/setools/roletypesquery.py new file mode 100644 index 00000000..7ef9b3ef --- /dev/null +++ b/setools/roletypesquery.py @@ -0,0 +1,36 @@ +# Copyright 2025, Christian Göttsche +# +# SPDX-License-Identifier: LGPL-2.1-only +# +from collections.abc import Iterable +import typing + +from . import mixins, policyrep, query + +__all__: typing.Final[tuple[str, ...]] = ("RoleTypesQuery",) + + +class RoleTypesQuery(mixins.MatchName, query.PolicyQuery): + + """ + Query SELinux policy roles. + + Parameter: + policy The policy to query. + + Keyword Parameters/Class attributes: + name The type name to match. + name_regex If true, regular expression matching + will be used on the type names. + """ + + def results(self) -> Iterable[policyrep.Role]: + """Generator which yields all matching roles.""" + self.log.info(f"Generating role-types results from {self.policy}") + self._match_name_debug(self.log) + + for r in self.policy.roles(): + for t in r.types(): + if self._match_name(t): + yield r + break diff --git a/tests/library/roletypesquery.conf b/tests/library/roletypesquery.conf new file mode 100644 index 00000000..7c02e77c --- /dev/null +++ b/tests/library/roletypesquery.conf @@ -0,0 +1,144 @@ +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 + +allow system system:infoflow3 null; + +######################################## +# +# Role Query +# + +# test 1 +type test1; + +# test 2 +role test2ra; +role test2rb; +type test2a; +type test2b; +role test2ra types { test2a test2b }; +role test2rb types test2b; + +# test 3 + +role test3ra; +role test3rb; +role test3rc; +role test3rd; +type test3a; +type test3b; +type test3c; +type test3d; +role test3ra types { test3b test3c test3d }; +role test3rb types { test3a test3c test3d }; +role test3rc types { test3a test3b test3d }; +role test3rd types { test3a test3b test3c }; + +################################################################################ + +#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/library/test_roletypesquery.py b/tests/library/test_roletypesquery.py new file mode 100644 index 00000000..cfcc4961 --- /dev/null +++ b/tests/library/test_roletypesquery.py @@ -0,0 +1,38 @@ +# Copyright 2025, Christian Göttsche +# +# SPDX-License-Identifier: GPL-2.0-only +# +import pytest +import setools + + +@pytest.mark.obj_args("tests/library/roletypesquery.conf") +class TestRoleTypesQuery: + + def test_name_nomatch(self, compiled_policy: setools.SELinuxPolicy) -> None: + """Type with no associated role.""" + q = setools.RoleTypesQuery(compiled_policy, name="test1") + + roles = sorted(str(r) for r in q.results()) + assert [] == roles + + def test_name_onematch(self, compiled_policy: setools.SELinuxPolicy) -> None: + """Type with one associated role.""" + q = setools.RoleTypesQuery(compiled_policy, name="test2a") + + roles = sorted(str(r) for r in q.results()) + assert ["test2ra"] == roles + + def test_name_multiplematches(self, compiled_policy: setools.SELinuxPolicy) -> None: + """Type with multiple associated roles.""" + q = setools.RoleTypesQuery(compiled_policy, name="test3a") + + roles = sorted(str(r) for r in q.results()) + assert ["test3rb", "test3rc", "test3rd"] == roles + + def test_name_multiplematches_regex(self, compiled_policy: setools.SELinuxPolicy) -> None: + """Multiple types with multiple associated roles.""" + q = setools.RoleTypesQuery(compiled_policy, name="test3", name_regex=True) + + roles = sorted(str(r) for r in q.results()) + assert ["test3ra", "test3rb", "test3rc", "test3rd"] == roles