blob: b4b900e843dbec977649120bc4aaa1e452cdfd23 [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
Jaekyun Seok64495e12018-01-30 17:08:54 +090013 compatible_property_only = False
Alex Klyubin9dd67db2017-04-06 20:14:43 -070014
15 def __init__(self, statement):
16 self.statement = statement
17 self.treble_only = False
Jaekyun Seok64495e12018-01-30 17:08:54 +090018 self.compatible_property_only = False
Alex Klyubin9dd67db2017-04-06 20:14:43 -070019
dcashmanb34ae0b2014-10-24 16:16:30 -070020
21# extract_neverallow_rules - takes an intermediate policy file and pulls out the
22# neverallow rules by taking all of the non-commented text between the 'neverallow'
23# keyword and a terminating ';'
Alex Klyubin9dd67db2017-04-06 20:14:43 -070024# returns: a list of rules
dcashmanb34ae0b2014-10-24 16:16:30 -070025def extract_neverallow_rules(policy_file):
26 with open(policy_file, 'r') as in_file:
27 policy_str = in_file.read()
Alex Klyubin9dd67db2017-04-06 20:14:43 -070028
29 # full-Treble only tests are inside sections delimited by BEGIN_TREBLE_ONLY
30 # and END_TREBLE_ONLY comments.
31
32 # uncomment TREBLE_ONLY section delimiter lines
33 remaining = re.sub(
Jaekyun Seok64495e12018-01-30 17:08:54 +090034 r'^\s*#\s*(BEGIN_TREBLE_ONLY|END_TREBLE_ONLY|BEGIN_COMPATIBLE_PROPERTY_ONLY|END_COMPATIBLE_PROPERTY_ONLY)',
Alex Klyubin9dd67db2017-04-06 20:14:43 -070035 r'\1',
36 policy_str,
37 flags = re.M)
dcashmanb34ae0b2014-10-24 16:16:30 -070038 # remove comments
Alex Klyubin9dd67db2017-04-06 20:14:43 -070039 remaining = re.sub(r'#.+?$', r'', remaining, flags = re.M)
dcashmanb34ae0b2014-10-24 16:16:30 -070040 # match neverallow rules
Alex Klyubin9dd67db2017-04-06 20:14:43 -070041 lines = re.findall(
Jaekyun Seok64495e12018-01-30 17:08:54 +090042 r'^\s*(neverallow\s.+?;|BEGIN_TREBLE_ONLY|END_TREBLE_ONLY|BEGIN_COMPATIBLE_PROPERTY_ONLY|END_COMPATIBLE_PROPERTY_ONLY)',
Alex Klyubin9dd67db2017-04-06 20:14:43 -070043 remaining,
44 flags = re.M |re.S)
45
46 # extract neverallow rules from the remaining lines
47 rules = list()
48 treble_only_depth = 0
Jaekyun Seok64495e12018-01-30 17:08:54 +090049 compatible_property_only_depth = 0
Alex Klyubin9dd67db2017-04-06 20:14:43 -070050 for line in lines:
51 if line.startswith("BEGIN_TREBLE_ONLY"):
52 treble_only_depth += 1
53 continue
54 elif line.startswith("END_TREBLE_ONLY"):
55 if treble_only_depth < 1:
56 exit("ERROR: END_TREBLE_ONLY outside of TREBLE_ONLY section")
57 treble_only_depth -= 1
58 continue
Jaekyun Seok64495e12018-01-30 17:08:54 +090059 elif line.startswith("BEGIN_COMPATIBLE_PROPERTY_ONLY"):
60 compatible_property_only_depth += 1
61 continue
62 elif line.startswith("END_COMPATIBLE_PROPERTY_ONLY"):
63 if compatible_property_only_depth < 1:
64 exit("ERROR: END_COMPATIBLE_PROPERTY_ONLY outside of COMPATIBLE_PROPERTY_ONLY section")
65 compatible_property_only_depth -= 1
66 continue
Alex Klyubin9dd67db2017-04-06 20:14:43 -070067 rule = NeverallowRule(line)
68 rule.treble_only = (treble_only_depth > 0)
Jaekyun Seok64495e12018-01-30 17:08:54 +090069 rule.compatible_property_only = (compatible_property_only_depth > 0)
Alex Klyubin9dd67db2017-04-06 20:14:43 -070070 rules.append(rule)
71
72 if treble_only_depth != 0:
73 exit("ERROR: end of input while inside TREBLE_ONLY section")
Jaekyun Seok64495e12018-01-30 17:08:54 +090074 if compatible_property_only_depth != 0:
75 exit("ERROR: end of input while inside COMPATIBLE_PROPERTY_ONLY section")
76
Alex Klyubin9dd67db2017-04-06 20:14:43 -070077 return rules
dcashmanb34ae0b2014-10-24 16:16:30 -070078
79# neverallow_rule_to_test - takes a neverallow statement and transforms it into
80# the output necessary to form a cts unit test in a java source file.
81# returns: a string representing a generic test method based on this rule.
Alex Klyubin9dd67db2017-04-06 20:14:43 -070082def neverallow_rule_to_test(rule, test_num):
83 squashed_neverallow = rule.statement.replace("\n", " ")
dcashmanb34ae0b2014-10-24 16:16:30 -070084 method = SELinuxNeverallowTestFrame.src_method
85 method = method.replace("testNeverallowRules()",
86 "testNeverallowRules" + str(test_num) + "()")
Alex Klyubin9dd67db2017-04-06 20:14:43 -070087 method = method.replace("$NEVERALLOW_RULE_HERE$", squashed_neverallow)
88 method = method.replace(
89 "$FULL_TREBLE_ONLY_BOOL_HERE$",
90 "true" if rule.treble_only else "false")
Jaekyun Seok64495e12018-01-30 17:08:54 +090091 method = method.replace(
92 "$COMPATIBLE_PROPERTY_ONLY_BOOL_HERE$",
93 "true" if rule.compatible_property_only else "false")
Alex Klyubin9dd67db2017-04-06 20:14:43 -070094 return method
dcashmanb34ae0b2014-10-24 16:16:30 -070095
96if __name__ == "__main__":
97 # check usage
98 if len(sys.argv) != 3:
99 print usage
Alex Klyubin4b6268f2017-04-06 20:27:46 -0700100 exit(1)
dcashmanb34ae0b2014-10-24 16:16:30 -0700101 input_file = sys.argv[1]
102 output_file = sys.argv[2]
103
104 src_header = SELinuxNeverallowTestFrame.src_header
105 src_body = SELinuxNeverallowTestFrame.src_body
106 src_footer = SELinuxNeverallowTestFrame.src_footer
107
108 # grab the neverallow rules from the policy file and transform into tests
109 neverallow_rules = extract_neverallow_rules(input_file)
110 i = 0
111 for rule in neverallow_rules:
112 src_body += neverallow_rule_to_test(rule, i)
113 i += 1
114
115 with open(output_file, 'w') as out_file:
116 out_file.write(src_header)
117 out_file.write(src_body)
118 out_file.write(src_footer)