File: test_rules.py

package info (click to toggle)
setools 4.6.0-2
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 3,600 kB
  • sloc: python: 24,485; makefile: 14
file content (217 lines) | stat: -rw-r--r-- 9,820 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
#
# SPDX-License-Identifier: GPL-2.0-only
#
from contextlib import suppress
import dataclasses
import enum

import pytest
import setools


@dataclasses.dataclass
class RuleTestCase:

    """
    Rule test case

    If the field is None, it is not supported by the rule type.
    """

    ruletype: enum.Enum
    source: str
    target: str
    statement: str
    type_: type  # the rule's policyrep class
    tclass: str | None = None
    xperm: str | None = None
    perms: set[str] | setools.XpermSet | None = None
    default: str | None = None
    filename: str | None = None
    conditional: str | None = None


rule_test_data = [
    RuleTestCase(setools.RBACRuletype.allow, "role21a_r", "role21b_r",
                 type_=setools.RoleAllow, statement="allow role21a_r role21b_r;"),
    RuleTestCase(setools.RBACRuletype.role_transition, "role21b_r", "type30",
                 type_=setools.RoleTransition, default="role20_r", tclass="infoflow",
                 statement="role_transition role21b_r type30:infoflow role20_r;"),
    RuleTestCase(setools.MLSRuletype.range_transition, "type30", "system", tclass="infoflow7",
                 default="s0:c1 - s2:c0.c4", type_=setools.MLSRule,
                 statement="range_transition type30 system:infoflow7 s0:c1 - s2:c0.c4;"),
    RuleTestCase(setools.TERuletype.allow, "system", "type30", tclass="infoflow3",
                 perms=set(("null",)), type_=setools.AVRule,
                 statement="allow system type30:infoflow3 null;"),
    RuleTestCase(setools.TERuletype.auditallow, "type31c", "type31a", tclass="infoflow6",
                 perms=set(("hi_r", "hi_w")), type_=setools.AVRule,
                 statement="auditallow type31c type31a:infoflow6 { hi_r hi_w };"),
    RuleTestCase(setools.TERuletype.dontaudit, "type31c", "type31b", tclass="infoflow7",
                 perms=set(("super_w", "super_r")), type_=setools.AVRule, conditional="a_bool",
                 statement="dontaudit type31c type31b:infoflow7 "
                           "{ super_r super_w }; [ a_bool ]:True"),
    RuleTestCase(setools.TERuletype.type_transition, "type31b", "system", tclass="infoflow4",
                 default="type30", type_=setools.FileNameTERule, filename="the_filename",
                 statement="type_transition type31b system:infoflow4 type30 the_filename;"),
    RuleTestCase(setools.TERuletype.type_change, "type31c", "type31b", tclass="infoflow2",
                 default="system", type_=setools.TERule, conditional="a_bool",
                 statement="type_change type31c type31b:infoflow2 system; [ a_bool ]:False"),
    RuleTestCase(setools.TERuletype.allowxperm, "type30", "type31a", tclass="infoflow",
                 xperm="ioctl", perms=setools.XpermSet((0x00ff,)), type_=setools.AVRuleXperm,
                 statement="allowxperm type30 type31a:infoflow ioctl 0x00ff;"),
    RuleTestCase(setools.TERuletype.auditallowxperm, "type31a", "type31b", tclass="infoflow",
                 xperm="nlmsg", perms=setools.XpermSet((1, 2, 3)), type_=setools.AVRuleXperm,
                 statement="auditallowxperm type31a type31b:infoflow nlmsg 0x0001-0x0003;")]


@pytest.mark.obj_args("tests/library/policyrep/rules.conf")
@pytest.mark.parametrize("testcase", rule_test_data)
class TestRules:

    @pytest.fixture(autouse=True)
    def _get_rules(self, compiled_policy: setools.SELinuxPolicy) -> None:
        self.rules = dict[enum.Enum, setools.policyrep.PolicyRule]()
        self.rules |= {r.ruletype: r for r in compiled_policy.terules()}
        self.rules |= {r.ruletype: r for r in compiled_policy.rbacrules()}
        self.rules |= {r.ruletype: r for r in compiled_policy.mlsrules()}

    def test_ruletype(self, testcase: RuleTestCase) -> None:
        """Rule type"""
        rule = self.rules[testcase.ruletype]
        assert testcase.ruletype == rule.ruletype, f"{testcase.ruletype} != {rule.ruletype}"
        assert isinstance(rule, testcase.type_), f"{type(rule)}, {rule=}"

    def test_source_type(self, testcase: RuleTestCase) -> None:
        """Source object"""
        rule = self.rules[testcase.ruletype]
        assert testcase.source == rule.source, f"{testcase.source} != {rule.source}"

    def test_target_type(self, testcase: RuleTestCase) -> None:
        """Target object"""
        rule = self.rules[testcase.ruletype]
        assert testcase.target == rule.target, f"{testcase.target} != {rule.target}"

    def test_object_class(self, testcase: RuleTestCase) -> None:
        """Object class"""
        rule = self.rules[testcase.ruletype]
        if testcase.tclass is None:
            with pytest.raises(setools.exception.RuleUseError):
                rule.tclass
        else:
            assert testcase.tclass == rule.tclass, f"{testcase.tclass} != {rule.tclass}"

    def test_xperm_type(self, testcase: RuleTestCase) -> None:
        """Extended permission type"""
        rule = self.rules[testcase.ruletype]
        if testcase.xperm is None:
            assert rule.extended is False
            with pytest.raises(setools.exception.RuleUseError):
                rule.xperm_type
        else:
            assert rule.extended is True
            assert testcase.xperm == rule.xperm_type, f"{testcase.xperm} != {rule.xperm_type}"

    def test_permissions_or_default(self, testcase: RuleTestCase) -> None:
        """Test default/permissions"""
        assert not (testcase.default is not None and testcase.perms is not None), \
            f"Test case setup error {testcase=}"

        rule = self.rules[testcase.ruletype]
        if testcase.perms is not None:
            assert testcase.perms == rule.perms, f"{testcase.perms} != {rule.perms}"
            with pytest.raises(setools.exception.RuleUseError):
                rule.default
        elif testcase.default is not None:
            assert testcase.default == rule.default, f"{testcase.default} != {rule.default}"
            with pytest.raises(setools.exception.RuleUseError):
                rule.perms
        else:
            with pytest.raises(setools.exception.RuleUseError):
                rule.perms

            with pytest.raises(setools.exception.RuleUseError):
                rule.default

    def test_conditional(self, testcase: RuleTestCase) -> None:
        """Conditional expression"""
        rule = self.rules[testcase.ruletype]
        if testcase.conditional is None:
            with pytest.raises(setools.exception.RuleNotConditional):
                rule.conditional

            with pytest.raises(setools.exception.RuleNotConditional):
                rule.conditional_block
        else:
            assert testcase.conditional == rule.conditional, f"{rule.conditional}"
            assert isinstance(rule.conditional_block, bool), f"{rule.conditional_block}"

    def test_filename(self, testcase: RuleTestCase) -> None:
        """Filename"""
        rule = self.rules[testcase.ruletype]
        if testcase.filename is None:
            if rule.ruletype == setools.TERuletype.type_transition:
                with pytest.raises(setools.exception.TERuleNoFilename):
                    rule.filename
            else:
                with pytest.raises(setools.exception.RuleUseError):
                    rule.filename
        else:
            assert testcase.filename == rule.filename, f"{testcase.filename} != {rule.filename}"

    def test_statement(self, testcase: RuleTestCase) -> None:
        """Statement"""
        rule = self.rules[testcase.ruletype]
        assert testcase.statement == rule.statement(), \
            f"\"{testcase.statement}\" != \"{rule.statement()}\""

    def test_expand(self, testcase: RuleTestCase) -> None:
        """Expand"""
        rule = self.rules[testcase.ruletype]
        for expanded_rule in rule.expand():
            assert isinstance(expanded_rule, type(rule))
            if expanded_rule is rule:
                # the rule can't be expanded
                pass
            else:
                assert expanded_rule.origin == rule
                assert expanded_rule.source in rule.source
                assert expanded_rule.target in rule.target

                with suppress(setools.exception.RuleUseError):
                    assert expanded_rule.tclass == rule.tclass

                with suppress(setools.exception.RuleUseError):
                    assert expanded_rule.xperm_type == rule.xperm_type

                with suppress(setools.exception.RuleUseError):
                    assert expanded_rule.perms == rule.perms

                with suppress(setools.exception.RuleUseError):
                    assert expanded_rule.default == rule.default

                with suppress(setools.exception.RuleNotConditional):
                    assert expanded_rule.conditional == rule.conditional
                    assert expanded_rule.conditional_block == rule.conditional_block

                with suppress(setools.exception.RuleUseError):
                    assert expanded_rule.filename == rule.filename


@pytest.mark.obj_args("tests/library/policyrep/terule_issue74.conf")
class TestAVRuleXpermIssue74:

    """
    Regression test for xperm ranges starting with 0x00 not being loaded.
    https://github.com/SELinuxProject/setools/issues/74
    """

    def test_regression(self, compiled_policy: setools.SELinuxPolicy):
        """Regression test for GitHub issue 74."""
        rules = sorted(compiled_policy.terules())
        assert 2 == len(rules)

        # expect 2 rules:
        # allowxperm init_type_t init_type_t : unix_dgram_socket ioctl { 0x8910 };
        # allowxperm init_type_t init_type_t : unix_dgram_socket ioctl { 0x0-0xff };
        assert setools.XpermSet(range(0x100)) == rules[0].perms, f"{rules[0].perms}"
        assert setools.XpermSet([0x8910]) == rules[1].perms, f"{rules[1].perms}"