• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1#!/usr/bin/env python
2
3import copy
4import re
5import sys
6import SELinuxNeverallowTestFrame
7
8usage = "Usage: ./SELinuxNeverallowTestGen.py <input policy file> <output cts java source>"
9
10
11class NeverallowRule:
12    statement = ''
13    depths = None
14
15    def __init__(self, statement, depths):
16        self.statement = statement
17        self.depths = copy.deepcopy(depths)
18
19# full-Treble only tests are inside sections delimited by BEGIN_{section} and
20# END_{section} comments.
21sections = ["TREBLE_ONLY", "COMPATIBLE_PROPERTY_ONLY", "LAUNCHING_WITH_R_ONLY"]
22
23# extract_neverallow_rules - takes an intermediate policy file and pulls out the
24# neverallow rules by taking all of the non-commented text between the 'neverallow'
25# keyword and a terminating ';'
26# returns: a list of rules
27def extract_neverallow_rules(policy_file):
28    with open(policy_file, 'r') as in_file:
29        policy_str = in_file.read()
30
31        # uncomment section delimiter lines
32        section_headers = '|'.join(['BEGIN_%s|END_%s' % (s, s) for s in sections])
33        remaining = re.sub(
34            r'^\s*#\s*(' + section_headers + ')',
35            r'\1',
36            policy_str,
37            flags = re.M)
38        # remove comments
39        remaining = re.sub(r'#.+?$', r'', remaining, flags = re.M)
40        # match neverallow rules
41        lines = re.findall(
42            r'^\s*(neverallow\s.+?;|' + section_headers + ')',
43            remaining,
44            flags = re.M |re.S)
45
46        # extract neverallow rules from the remaining lines
47        rules = list()
48        depths = dict()
49        for section in sections:
50            depths[section] = 0
51        for line in lines:
52            is_header = False
53            for section in sections:
54                if line.startswith("BEGIN_%s" % section):
55                    depths[section] += 1
56                    is_header = True
57                    break
58                elif line.startswith("END_%s" % section):
59                    if depths[section] < 1:
60                        exit("ERROR: END_%s outside of %s section" % (section, section))
61                    depths[section] -= 1
62                    is_header = True
63                    break
64            if not is_header:
65                rule = NeverallowRule(line, depths)
66                rules.append(rule)
67
68        for section in sections:
69            if depths[section] != 0:
70                exit("ERROR: end of input while inside %s section" % section)
71
72        return rules
73
74# neverallow_rule_to_test - takes a neverallow statement and transforms it into
75# the output necessary to form a cts unit test in a java source file.
76# returns: a string representing a generic test method based on this rule.
77def neverallow_rule_to_test(rule, test_num):
78    squashed_neverallow = rule.statement.replace("\n", " ")
79    method  = SELinuxNeverallowTestFrame.src_method
80    method = method.replace("testNeverallowRules()",
81        "testNeverallowRules" + str(test_num) + "()")
82    method = method.replace("$NEVERALLOW_RULE_HERE$", squashed_neverallow)
83    for section in sections:
84        method = method.replace(
85            "$%s_BOOL_HERE$" % section,
86            "true" if rule.depths[section] else "false")
87    return method
88
89if __name__ == "__main__":
90    # check usage
91    if len(sys.argv) != 3:
92        print usage
93        exit(1)
94    input_file = sys.argv[1]
95    output_file = sys.argv[2]
96
97    src_header = SELinuxNeverallowTestFrame.src_header
98    src_body = SELinuxNeverallowTestFrame.src_body
99    src_footer = SELinuxNeverallowTestFrame.src_footer
100
101    # grab the neverallow rules from the policy file and transform into tests
102    neverallow_rules = extract_neverallow_rules(input_file)
103    i = 0
104    for rule in neverallow_rules:
105        src_body += neverallow_rule_to_test(rule, i)
106        i += 1
107
108    with open(output_file, 'w') as out_file:
109        out_file.write(src_header)
110        out_file.write(src_body)
111        out_file.write(src_footer)
112