blob: e74ba781f083711d15f2a725e158ef1d79837758 [file] [log] [blame]
dcashman9b615752015-01-07 14:23:11 -08001#!/usr/bin/env python
dcashmanb34ae0b2014-10-24 16:16:30 -07002
3import re
4import sys
5import SELinuxNeverallowTestFrame
6
Alex Klyubin9dd67db2017-04-06 20:14:43 -07007usage = "Usage: ./SELinuxNeverallowTestGen.py <input policy file> <output cts java source>"
8
9
10class NeverallowRule:
11 statement = ''
12 treble_only = False
13
14 def __init__(self, statement):
15 self.statement = statement
16 self.treble_only = False
17
dcashmanb34ae0b2014-10-24 16:16:30 -070018
19# extract_neverallow_rules - takes an intermediate policy file and pulls out the
20# neverallow rules by taking all of the non-commented text between the 'neverallow'
21# keyword and a terminating ';'
Alex Klyubin9dd67db2017-04-06 20:14:43 -070022# returns: a list of rules
dcashmanb34ae0b2014-10-24 16:16:30 -070023def extract_neverallow_rules(policy_file):
24 with open(policy_file, 'r') as in_file:
25 policy_str = in_file.read()
Alex Klyubin9dd67db2017-04-06 20:14:43 -070026
27 # full-Treble only tests are inside sections delimited by BEGIN_TREBLE_ONLY
28 # and END_TREBLE_ONLY comments.
29
30 # uncomment TREBLE_ONLY section delimiter lines
31 remaining = re.sub(
32 r'^\s*#\s*(BEGIN_TREBLE_ONLY|END_TREBLE_ONLY)',
33 r'\1',
34 policy_str,
35 flags = re.M)
dcashmanb34ae0b2014-10-24 16:16:30 -070036 # remove comments
Alex Klyubin9dd67db2017-04-06 20:14:43 -070037 remaining = re.sub(r'#.+?$', r'', remaining, flags = re.M)
dcashmanb34ae0b2014-10-24 16:16:30 -070038 # match neverallow rules
Alex Klyubin9dd67db2017-04-06 20:14:43 -070039 lines = re.findall(
40 r'^\s*(neverallow\s.+?;|BEGIN_TREBLE_ONLY|END_TREBLE_ONLY)',
41 remaining,
42 flags = re.M |re.S)
43
44 # extract neverallow rules from the remaining lines
45 rules = list()
46 treble_only_depth = 0
47 for line in lines:
48 if line.startswith("BEGIN_TREBLE_ONLY"):
49 treble_only_depth += 1
50 continue
51 elif line.startswith("END_TREBLE_ONLY"):
52 if treble_only_depth < 1:
53 exit("ERROR: END_TREBLE_ONLY outside of TREBLE_ONLY section")
54 treble_only_depth -= 1
55 continue
56 rule = NeverallowRule(line)
57 rule.treble_only = (treble_only_depth > 0)
58 rules.append(rule)
59
60 if treble_only_depth != 0:
61 exit("ERROR: end of input while inside TREBLE_ONLY section")
62 return rules
dcashmanb34ae0b2014-10-24 16:16:30 -070063
64# neverallow_rule_to_test - takes a neverallow statement and transforms it into
65# the output necessary to form a cts unit test in a java source file.
66# returns: a string representing a generic test method based on this rule.
Alex Klyubin9dd67db2017-04-06 20:14:43 -070067def neverallow_rule_to_test(rule, test_num):
68 squashed_neverallow = rule.statement.replace("\n", " ")
dcashmanb34ae0b2014-10-24 16:16:30 -070069 method = SELinuxNeverallowTestFrame.src_method
70 method = method.replace("testNeverallowRules()",
71 "testNeverallowRules" + str(test_num) + "()")
Alex Klyubin9dd67db2017-04-06 20:14:43 -070072 method = method.replace("$NEVERALLOW_RULE_HERE$", squashed_neverallow)
73 method = method.replace(
74 "$FULL_TREBLE_ONLY_BOOL_HERE$",
75 "true" if rule.treble_only else "false")
76 return method
dcashmanb34ae0b2014-10-24 16:16:30 -070077
78if __name__ == "__main__":
79 # check usage
80 if len(sys.argv) != 3:
81 print usage
Alex Klyubin4b6268f2017-04-06 20:27:46 -070082 exit(1)
dcashmanb34ae0b2014-10-24 16:16:30 -070083 input_file = sys.argv[1]
84 output_file = sys.argv[2]
85
86 src_header = SELinuxNeverallowTestFrame.src_header
87 src_body = SELinuxNeverallowTestFrame.src_body
88 src_footer = SELinuxNeverallowTestFrame.src_footer
89
90 # grab the neverallow rules from the policy file and transform into tests
91 neverallow_rules = extract_neverallow_rules(input_file)
92 i = 0
93 for rule in neverallow_rules:
94 src_body += neverallow_rule_to_test(rule, i)
95 i += 1
96
97 with open(output_file, 'w') as out_file:
98 out_file.write(src_header)
99 out_file.write(src_body)
100 out_file.write(src_footer)