move selinux tools to cts/tools/selinux

CTS shouldn't be depending on packages/experimental. Move
all the SELinux scripts/code from that directory to CTS
proper.

Bug: 17301255
Bug: 17593625
Change-Id: If43efc6aab803d1089adc03bafe8621955778730
diff --git a/tools/selinux/test/testrunner.py b/tools/selinux/test/testrunner.py
new file mode 100755
index 0000000..bc424e9
--- /dev/null
+++ b/tools/selinux/test/testrunner.py
@@ -0,0 +1,442 @@
+#!/usr/bin/python
+import sys
+sys.path.append('../src')
+import unittest
+import SELinux_CTS
+from SELinux_CTS import SELinuxPolicy
+
+policy_file_name = 'policy_test.conf'
+types = set([
+        'bluetooth',
+        'healthd',
+        'healthd_exec',
+        'testTYPE' ])  #testTYPE added for neverallow rule to make sense
+attributes = {
+    'domain': set(['bluetooth', 'healthd', 'testTYPE']),
+    'unconfineddomain': set(['bluetooth']),
+    'appdomain': set(['bluetooth', 'testTYPE']),
+    'file_type': set(['healthd_exec']),
+    'exec_type': set(['healthd_exec']) }
+common_classes = {
+    'file': set([
+            'ioctl',
+            'read',
+            'write',
+            'create',
+            'getattr',
+            'setattr',
+            'lock',
+            'relabelfrom',
+            'relabelto',
+            'append',
+            'unlink',
+            'link',
+            'rename',
+            'execute',
+            'swapon',
+            'quotaon',
+            'mounton' ]) }
+classes = {
+    'capability': set([
+            'chown',
+            'dac_override',
+            'dac_read_search',
+            'fowner',
+            'fsetid',
+            'kill',
+            'setgid',
+            'setuid',
+            'setpcap',
+            'linux_immutable',
+            'net_bind_service',
+            'net_broadcast',
+            'net_admin',
+            'net_raw',
+            'ipc_lock',
+            'ipc_owner',
+            'sys_module',
+            'sys_rawio',
+            'sys_chroot',
+            'sys_ptrace',
+            'sys_pacct',
+            'sys_admin',
+            'sys_boot',
+            'sys_nice',
+            'sys_resource',
+            'sys_time',
+            'sys_tty_config',
+            'mknod',
+            'lease',
+            'audit_write',
+            'audit_control',
+            'setfcap' ]),
+    'file': (set([
+                'execute_no_trans',
+                'entrypoint',
+                'execmod',
+                'open',
+                'audit_access' ]) | common_classes['file']) }
+
+# allow healthd healthd_exec:file { entrypoint read execute };
+allow_rules = [
+    { 'source_types': {
+        'set': set([
+                'healthd']),
+        'flags': { 'complement': False } },
+      'target_types': {
+        'set': set([
+                'healthd_exec']),
+        'flags': { 'complement': False } },
+      'classes': {
+        'set': set([
+                'file']),
+        'flags': { 'complement': False } },
+      'permissions': {
+        'set': set([
+                'entrypoint',
+                'read',
+                'execute' ]),
+        'flags': { 'complement': False } } } ]
+
+# neverallow { appdomain -unconfineddomain -bluetooth } self:capability *;
+neverallow_rules = [
+    { 'source_types': {
+        'set': set([
+                'appdomain',
+                '-unconfineddomain',
+                '-bluetooth' ]),
+        'flags': { 'complement': False } },
+      'target_types': {
+        'set': set([
+                'self']),
+        'flags': { 'complement': False } },
+      'classes': {
+        'set': set([
+                'capability']),
+        'flags': { 'complement': False } },
+      'permissions': {
+        'set': set([
+                '*' ]),
+        'flags': { 'complement': False } } } ]
+
+expected_final_allow_list = [
+        [ ('healthd', 'healthd_exec', 'file', 'entrypoint'),
+                ('healthd', 'healthd_exec', 'file', 'read'),
+                ('healthd', 'healthd_exec', 'file', 'execute') ] ]
+
+expected_final_neverallow_list = [
+        [ ('testTYPE', 'testTYPE', 'capability', 'chown'),
+                ('testTYPE', 'testTYPE', 'capability', 'dac_override'),
+                ('testTYPE', 'testTYPE', 'capability', 'dac_read_search'),
+                ('testTYPE', 'testTYPE', 'capability', 'fowner'),
+                ('testTYPE', 'testTYPE', 'capability', 'fsetid'),
+                ('testTYPE', 'testTYPE', 'capability', 'kill'),
+                ('testTYPE', 'testTYPE', 'capability', 'setgid'),
+                ('testTYPE', 'testTYPE', 'capability', 'setuid'),
+                ('testTYPE', 'testTYPE', 'capability', 'setpcap'),
+                ('testTYPE', 'testTYPE', 'capability', 'linux_immutable'),
+                ('testTYPE', 'testTYPE', 'capability', 'net_bind_service'),
+                ('testTYPE', 'testTYPE', 'capability', 'net_broadcast'),
+                ('testTYPE', 'testTYPE', 'capability', 'net_admin'),
+                ('testTYPE', 'testTYPE', 'capability', 'net_raw'),
+                ('testTYPE', 'testTYPE', 'capability', 'ipc_lock'),
+                ('testTYPE', 'testTYPE', 'capability', 'ipc_owner'),
+                ('testTYPE', 'testTYPE', 'capability', 'sys_module'),
+                ('testTYPE', 'testTYPE', 'capability', 'sys_rawio'),
+                ('testTYPE', 'testTYPE', 'capability', 'sys_chroot'),
+                ('testTYPE', 'testTYPE', 'capability', 'sys_ptrace'),
+                ('testTYPE', 'testTYPE', 'capability', 'sys_pacct'),
+                ('testTYPE', 'testTYPE', 'capability', 'sys_admin'),
+                ('testTYPE', 'testTYPE', 'capability', 'sys_boot'),
+                ('testTYPE', 'testTYPE', 'capability', 'sys_nice'),
+                ('testTYPE', 'testTYPE', 'capability', 'sys_resource'),
+                ('testTYPE', 'testTYPE', 'capability', 'sys_time'),
+                ('testTYPE', 'testTYPE', 'capability', 'sys_tty_config'),
+                ('testTYPE', 'testTYPE', 'capability', 'mknod'),
+                ('testTYPE', 'testTYPE', 'capability', 'lease'),
+                ('testTYPE', 'testTYPE', 'capability', 'audit_write'),
+                ('testTYPE', 'testTYPE', 'capability', 'audit_control'),
+                ('testTYPE', 'testTYPE', 'capability', 'setfcap') ] ]
+
+
+class SELinuxPolicyTests(unittest.TestCase):
+
+
+    def setUp(self):
+        self.test_policy = SELinuxPolicy()
+        self.test_file = open(policy_file_name, 'r')
+        self.test_policy.types = types
+        self.test_policy.attributes = attributes
+        self.test_policy.common_classes = common_classes
+        self.test_policy.classes = classes
+        self.test_policy.allow_rules = allow_rules
+        self.test_policy.neverallow_rules = neverallow_rules
+        return
+
+    def testExpandAvcRule(self):
+        #TODO: add more examples here to cover different cases
+        expanded_allow_list = SELinux_CTS.expand_avc_rule(self.test_policy, self.test_policy.allow_rules[0])
+        for a in expected_final_allow_list[0]:
+            self.failUnless(a in expanded_allow_list)
+        expanded_neverallow_list = SELinux_CTS.expand_avc_rule(self.test_policy, self.test_policy.neverallow_rules[0])
+        for n in expected_final_neverallow_list[0]:
+            self.failUnless(n in expanded_neverallow_list)
+
+    def testExpandBrackets(self):
+        #test position without bracket:
+        self.test_file.seek(279)
+        self.failIf(SELinux_CTS.expand_brackets(self.test_file))
+
+        #test position with bracket:
+        self.test_file.seek(26123)
+        self.failUnless(SELinux_CTS.expand_brackets(self.test_file) == " entrypoint read execute ")
+
+        #test position with nested brackets:
+        self.test_file.seek(26873)
+        self.failUnless(SELinux_CTS.expand_brackets(self.test_file)
+               == " dir   chr_file blk_file   file lnk_file sock_file fifo_file   ")
+
+    def testGetAvcRuleComponent(self):
+        #test against normal ('allow healthd healthd_exec:file ...)
+        self.test_file.seek(26096)
+        normal_src = { 'flags': { 'complement': False },
+                'set': set(['healthd']) }
+        normal_tgt = { 'flags': { 'complement': False },
+                'set': set(['healthd_exec']) }
+        normal_class = { 'flags': { 'complement': False },
+                'set': set(['file']) }
+        normal_perm = { 'flags': { 'complement': False },
+                'set': set(['entrypoint', 'read', 'execute']) }
+        self.failUnless(SELinux_CTS.get_avc_rule_component(self.test_file)
+            == normal_src)
+        self.failUnless(SELinux_CTS.get_avc_rule_component(self.test_file)
+            == normal_tgt)
+        c = SELinux_CTS.advance_past_whitespace(self.test_file)
+        if c == ':':
+            self.test_file.read(1)
+        self.failUnless(SELinux_CTS.get_avc_rule_component(self.test_file)
+            == normal_class)
+        self.failUnless(SELinux_CTS.get_avc_rule_component(self.test_file)
+            == normal_perm)
+
+        #test against 'hard' ('init {fs_type  ...' )
+        self.test_file.seek(26838)
+        hard_src = { 'flags': { 'complement': False },
+                'set': set(['init']) }
+        hard_tgt = { 'flags': { 'complement': False },
+                'set': set(['fs_type', 'dev_type', 'file_type']) }
+        hard_class = { 'flags': { 'complement': False },
+                'set': set(['dir', 'chr_file', 'blk_file', 'file', 'lnk_file', 'sock_file', 'fifo_file']) }
+        hard_perm = { 'flags': { 'complement': False },
+                'set': set(['relabelto']) }
+        self.failUnless(SELinux_CTS.get_avc_rule_component(self.test_file)
+            == hard_src)
+        self.failUnless(SELinux_CTS.get_avc_rule_component(self.test_file)
+            == hard_tgt)
+        #mimic ':' check:
+        c = SELinux_CTS.advance_past_whitespace(self.test_file)
+        if c == ':':
+            self.test_file.read(1)
+        self.failUnless(SELinux_CTS.get_avc_rule_component(self.test_file)
+            == hard_class)
+        self.failUnless(SELinux_CTS.get_avc_rule_component(self.test_file)
+            == hard_perm)
+
+        #test against 'multi-line' ('init {fs_type  ...' )
+        self.test_file.seek(26967)
+        multi_src = { 'flags': { 'complement': False },
+                'set': set(['appdomain', '-unconfineddomain']) }
+        multi_tgt = { 'flags': { 'complement': False },
+                'set': set(['audio_device', 'camera_device', 'dm_device', 'radio_device', 'gps_device', 'rpmsg_device']) }
+        multi_class = { 'flags': { 'complement': False },
+                'set': set(['chr_file']) }
+        multi_perm = { 'flags': { 'complement': False },
+                'set': set(['read', 'write']) }
+        self.failUnless(SELinux_CTS.get_avc_rule_component(self.test_file)
+            == multi_src)
+        self.failUnless(SELinux_CTS.get_avc_rule_component(self.test_file)
+            == multi_tgt)
+        c = SELinux_CTS.advance_past_whitespace(self.test_file)
+        if c == ':':
+            self.test_file.read(1)
+        self.failUnless(SELinux_CTS.get_avc_rule_component(self.test_file)
+            == multi_class)
+        self.failUnless(SELinux_CTS.get_avc_rule_component(self.test_file)
+            == multi_perm)
+
+        #test against 'complement'
+        self.test_file.seek(26806)
+        complement = { 'flags': { 'complement': True },
+                'set': set(['entrypoint', 'relabelto']) }
+        self.failUnless(SELinux_CTS.get_avc_rule_component(self.test_file)
+            == complement)
+
+    def testGetLineType(self):
+        self.failUnless(SELinux_CTS.get_line_type('type bluetooth, domain;')
+                == SELinux_CTS.TYPE)
+        self.failUnless(SELinux_CTS.get_line_type('attribute unconfineddomain;')
+                == SELinux_CTS.ATTRIBUTE)
+        self.failUnless(SELinux_CTS.get_line_type('typeattribute bluetooth appdomain;')
+                == SELinux_CTS.TYPEATTRIBUTE)
+        self.failUnless(SELinux_CTS.get_line_type('class file')
+                == SELinux_CTS.CLASS)
+        self.failUnless(SELinux_CTS.get_line_type('common file')
+                == SELinux_CTS.COMMON)
+        self.failUnless(SELinux_CTS.get_line_type('allow healthd healthd_exec:file { entrypoint read execute };')
+                == SELinux_CTS.ALLOW_RULE)
+        self.failUnless(SELinux_CTS.get_line_type('neverallow { appdomain -unconfineddomain -bluetooth } self:capability *;')
+                == SELinux_CTS.NEVERALLOW_RULE)
+        self.failUnless(SELinux_CTS.get_line_type('# FLASK')
+                == SELinux_CTS.OTHER)
+
+    def testIsMultiLine(self):
+        self.failIf(SELinux_CTS.is_multi_line(SELinux_CTS.TYPE))
+        self.failIf(SELinux_CTS.is_multi_line(SELinux_CTS.ATTRIBUTE))
+        self.failIf(SELinux_CTS.is_multi_line(SELinux_CTS.TYPEATTRIBUTE))
+        self.failUnless(SELinux_CTS.is_multi_line(SELinux_CTS.CLASS))
+        self.failUnless(SELinux_CTS.is_multi_line(SELinux_CTS.COMMON))
+        self.failUnless(SELinux_CTS.is_multi_line(SELinux_CTS.ALLOW_RULE))
+        self.failUnless(SELinux_CTS.is_multi_line(SELinux_CTS.NEVERALLOW_RULE))
+        self.failIf(SELinux_CTS.is_multi_line(SELinux_CTS.OTHER))
+
+    def testProcessInheritsSegment(self):
+        inherit_offset = 448 # needs changing if file changes
+        self.test_file.seek(inherit_offset, 0)
+        inherit_result = SELinux_CTS.process_inherits_segment(self.test_file)
+        self.failUnless(inherit_result == 'file')
+        return
+
+    def testFromFileName(self):
+        #using a special file, since the test_file has some lines which don't 'jive'
+        clean_policy_file = 'policy_clean_test.conf'
+        from_file_policy = SELinuxPolicy()
+        from_file_policy.from_file_name(clean_policy_file)
+        self.failUnless(from_file_policy.types == self.test_policy.types)
+        self.failUnless(from_file_policy.attributes == self.test_policy.attributes)
+        self.failUnless(from_file_policy.classes == self.test_policy.classes)
+        self.failUnless(from_file_policy.common_classes == self.test_policy.common_classes)
+        self.failUnless(from_file_policy.allow_rules == self.test_policy.allow_rules)
+        self.failUnless(from_file_policy.neverallow_rules == self.test_policy.neverallow_rules)
+
+    def testExpandPermissions(self):
+        #test general case
+        test_class_obj = 'file'
+        general_set = set(['read', 'write', 'execute'])
+        expanded_general_set = general_set
+        self.failUnless(self.test_policy.expand_permissions(test_class_obj, general_set)
+                == general_set)
+        star_set = set(['*'])
+        expanded_star_set = self.test_policy.classes['file'] #everything in the class
+        self.failUnless(self.test_policy.expand_permissions(test_class_obj, star_set)
+                == expanded_star_set)
+        complement_set = set(['*', '-open'])
+        expanded_complement_set = self.test_policy.classes['file'] - set(['open'])
+        self.failUnless(self.test_policy.expand_permissions(test_class_obj, complement_set)
+                == expanded_complement_set)
+
+    def testExpandTypes(self):
+
+        #test general case and '-' handling
+        test_source_set = set([
+                'domain',
+                '-bluetooth' ])
+        expanded_test_source_set = set([
+                'healthd', 'testTYPE' ])
+        self.failUnless(self.test_policy.expand_types(test_source_set) == expanded_test_source_set)
+
+        #test '*' handling
+        test_source_set = set([ '*' ])
+        expanded_test_source_set = set([
+                'bluetooth', 'healthd', 'testTYPE' ])
+        self.failUnless(self.test_policy.expand_types(test_source_set) == types)
+        #test - handling
+        test_source_set = set([
+                '*',
+                '-bluetooth'])
+        expanded_test_source_set = set([
+                'healthd', 'healthd_exec', 'testTYPE' ])
+        self.failUnless(self.test_policy.expand_types(test_source_set) == expanded_test_source_set)
+
+    def testProcessAttributeLine(self):
+        attribute_policy = SELinuxPolicy()
+        #test with 'normal input'
+        test_normal_string = 'attribute TEST_att;'
+        test_attribute = 'TEST_att'
+        attribute_policy.process_attribute_line(test_normal_string)
+        self.failUnless( test_attribute in attribute_policy.attributes)
+        #TODO: test on bogus inputs
+
+    def testProcessClassLine(self):
+        class_policy = SELinuxPolicy()
+        #offsets need changing if test file changes
+        common_offset  = 279
+        class_initial_offset  = 212
+        class_perm_offset = 437
+        self.test_file.seek(common_offset, 0)
+        line = self.test_file.readline()
+        class_policy.process_common_line(line, self.test_file)
+        self.test_file.seek(class_initial_offset, 0)
+        line = self.test_file.readline()
+        class_policy.process_class_line(line, self.test_file)
+        self.failUnless('file' in class_policy.classes)
+        self.test_file.seek(class_perm_offset, 0)
+        line = self.test_file.readline()
+        class_policy.process_class_line(line, self.test_file)
+        self.failUnless(class_policy.classes['file'] == classes['file'])
+
+    def testProcessCommonLine(self):
+        common_policy = SELinuxPolicy()
+        common_offset  = 279 # needs changing if file changes
+        self.test_file.seek(common_offset, 0)
+        line = self.test_file.readline()
+        common_policy.process_common_line(line, self.test_file)
+        self.failUnless('file' in common_policy.common_classes )
+        self.failUnless(common_policy.common_classes['file'] == common_classes['file'])
+
+    def testProcessAvcRuleLine(self):
+        avc_policy = SELinuxPolicy()
+        allow_offset  =  26091 # needs changing if file changes
+        neverallow_offset  = 26311  # needs changing if file changes
+        self.test_file.seek(allow_offset, 0)
+        line = self.test_file.readline()
+        avc_policy.process_avc_rule_line(line, self.test_file)
+        self.failUnless(avc_policy.allow_rules[0] == allow_rules[0] ) # always '0'?
+        self.test_file.seek(neverallow_offset, 0)
+        line = self.test_file.readline()
+        avc_policy.process_avc_rule_line(line, self.test_file)
+        self.failUnless(avc_policy.neverallow_rules[0] == neverallow_rules[0] ) # always '0'?
+
+    def testProcessTypeLine(self):
+        type_policy = SELinuxPolicy()
+        test_normal_string = 'type TEST_type, TEST_att1, TEST_att2;'
+        test_type = 'TEST_type'
+        test_atts = ['TEST_att1', 'TEST_att2']
+        #test with 'normal input'
+        type_policy.process_type_line(test_normal_string)
+        self.failUnless(test_type in type_policy.types)
+        for a in test_atts:
+            self.failUnless(a in type_policy.attributes)
+            self.failUnless(test_type in type_policy.attributes[a])
+        #TODO: test with domain only, no attributes
+        # and test on bogus inputs
+
+    def testProcessTypeattributeLine(self):
+        typ_att_policy = SELinuxPolicy()
+        test_normal_string = 'typeattribute TEST_type TEST_att1, TEST_att2;'
+        test_type = 'TEST_type'
+        test_atts = ['TEST_att1', 'TEST_att2']
+        #test with 'normal input' (type should already be declared)
+        typ_att_policy.process_type_line('type ' + test_type + ';')
+        typ_att_policy.process_typeattribute_line(test_normal_string)
+        self.failUnless(test_type in typ_att_policy.types)
+        for a in test_atts:
+            self.failUnless(a in typ_att_policy.attributes)
+            self.failUnless(test_type in typ_att_policy.attributes[a])
+        #TODO: test with domain only, no attributes
+        # and test on bogus inputs
+
+def main():
+    unittest.main()
+
+if __name__ == '__main__':
+    main()