Home | History | Annotate | Download | only in selinux
      1 #!/usr/bin/env python
      2 
      3 import re
      4 import sys
      5 import SELinuxNeverallowTestFrame
      6 
      7 usage = "Usage: ./SELinuxNeverallowTestGen.py <input policy file> <output cts java source>"
      8 
      9 
     10 class NeverallowRule:
     11     statement = ''
     12     treble_only = False
     13 
     14     def __init__(self, statement):
     15         self.statement = statement
     16         self.treble_only = False
     17 
     18 
     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 ';'
     22 # returns: a list of rules
     23 def extract_neverallow_rules(policy_file):
     24     with open(policy_file, 'r') as in_file:
     25         policy_str = in_file.read()
     26 
     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)
     36         # remove comments
     37         remaining = re.sub(r'#.+?$', r'', remaining, flags = re.M)
     38         # match neverallow rules
     39         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
     63 
     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.
     67 def neverallow_rule_to_test(rule, test_num):
     68     squashed_neverallow = rule.statement.replace("\n", " ")
     69     method  = SELinuxNeverallowTestFrame.src_method
     70     method = method.replace("testNeverallowRules()",
     71         "testNeverallowRules" + str(test_num) + "()")
     72     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
     77 
     78 if __name__ == "__main__":
     79     # check usage
     80     if len(sys.argv) != 3:
     81         print usage
     82         exit(1)
     83     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)
    101