Home | History | Annotate | Download | only in test
      1 #!/usr/bin/python
      2 import sys
      3 sys.path.append('../src')
      4 import unittest
      5 import SELinux_CTS
      6 from SELinux_CTS import SELinuxPolicy
      7 
      8 policy_file_name = 'policy_test.conf'
      9 types = set([
     10         'bluetooth',
     11         'healthd',
     12         'healthd_exec',
     13         'testTYPE' ])  #testTYPE added for neverallow rule to make sense
     14 attributes = {
     15     'domain': set(['bluetooth', 'healthd', 'testTYPE']),
     16     'unconfineddomain': set(['bluetooth']),
     17     'appdomain': set(['bluetooth', 'testTYPE']),
     18     'file_type': set(['healthd_exec']),
     19     'exec_type': set(['healthd_exec']) }
     20 common_classes = {
     21     'file': set([
     22             'ioctl',
     23             'read',
     24             'write',
     25             'create',
     26             'getattr',
     27             'setattr',
     28             'lock',
     29             'relabelfrom',
     30             'relabelto',
     31             'append',
     32             'unlink',
     33             'link',
     34             'rename',
     35             'execute',
     36             'swapon',
     37             'quotaon',
     38             'mounton' ]) }
     39 classes = {
     40     'capability': set([
     41             'chown',
     42             'dac_override',
     43             'dac_read_search',
     44             'fowner',
     45             'fsetid',
     46             'kill',
     47             'setgid',
     48             'setuid',
     49             'setpcap',
     50             'linux_immutable',
     51             'net_bind_service',
     52             'net_broadcast',
     53             'net_admin',
     54             'net_raw',
     55             'ipc_lock',
     56             'ipc_owner',
     57             'sys_module',
     58             'sys_rawio',
     59             'sys_chroot',
     60             'sys_ptrace',
     61             'sys_pacct',
     62             'sys_admin',
     63             'sys_boot',
     64             'sys_nice',
     65             'sys_resource',
     66             'sys_time',
     67             'sys_tty_config',
     68             'mknod',
     69             'lease',
     70             'audit_write',
     71             'audit_control',
     72             'setfcap' ]),
     73     'file': (set([
     74                 'execute_no_trans',
     75                 'entrypoint',
     76                 'execmod',
     77                 'open',
     78                 'audit_access' ]) | common_classes['file']) }
     79 
     80 # allow healthd healthd_exec:file { entrypoint read execute };
     81 allow_rules = [
     82     { 'source_types': {
     83         'set': set([
     84                 'healthd']),
     85         'flags': { 'complement': False } },
     86       'target_types': {
     87         'set': set([
     88                 'healthd_exec']),
     89         'flags': { 'complement': False } },
     90       'classes': {
     91         'set': set([
     92                 'file']),
     93         'flags': { 'complement': False } },
     94       'permissions': {
     95         'set': set([
     96                 'entrypoint',
     97                 'read',
     98                 'execute' ]),
     99         'flags': { 'complement': False } } } ]
    100 
    101 # neverallow { appdomain -unconfineddomain -bluetooth } self:capability *;
    102 neverallow_rules = [
    103     { 'source_types': {
    104         'set': set([
    105                 'appdomain',
    106                 '-unconfineddomain',
    107                 '-bluetooth' ]),
    108         'flags': { 'complement': False } },
    109       'target_types': {
    110         'set': set([
    111                 'self']),
    112         'flags': { 'complement': False } },
    113       'classes': {
    114         'set': set([
    115                 'capability']),
    116         'flags': { 'complement': False } },
    117       'permissions': {
    118         'set': set([
    119                 '*' ]),
    120         'flags': { 'complement': False } } } ]
    121 
    122 expected_final_allow_list = [
    123         [ ('healthd', 'healthd_exec', 'file', 'entrypoint'),
    124                 ('healthd', 'healthd_exec', 'file', 'read'),
    125                 ('healthd', 'healthd_exec', 'file', 'execute') ] ]
    126 
    127 expected_final_neverallow_list = [
    128         [ ('testTYPE', 'testTYPE', 'capability', 'chown'),
    129                 ('testTYPE', 'testTYPE', 'capability', 'dac_override'),
    130                 ('testTYPE', 'testTYPE', 'capability', 'dac_read_search'),
    131                 ('testTYPE', 'testTYPE', 'capability', 'fowner'),
    132                 ('testTYPE', 'testTYPE', 'capability', 'fsetid'),
    133                 ('testTYPE', 'testTYPE', 'capability', 'kill'),
    134                 ('testTYPE', 'testTYPE', 'capability', 'setgid'),
    135                 ('testTYPE', 'testTYPE', 'capability', 'setuid'),
    136                 ('testTYPE', 'testTYPE', 'capability', 'setpcap'),
    137                 ('testTYPE', 'testTYPE', 'capability', 'linux_immutable'),
    138                 ('testTYPE', 'testTYPE', 'capability', 'net_bind_service'),
    139                 ('testTYPE', 'testTYPE', 'capability', 'net_broadcast'),
    140                 ('testTYPE', 'testTYPE', 'capability', 'net_admin'),
    141                 ('testTYPE', 'testTYPE', 'capability', 'net_raw'),
    142                 ('testTYPE', 'testTYPE', 'capability', 'ipc_lock'),
    143                 ('testTYPE', 'testTYPE', 'capability', 'ipc_owner'),
    144                 ('testTYPE', 'testTYPE', 'capability', 'sys_module'),
    145                 ('testTYPE', 'testTYPE', 'capability', 'sys_rawio'),
    146                 ('testTYPE', 'testTYPE', 'capability', 'sys_chroot'),
    147                 ('testTYPE', 'testTYPE', 'capability', 'sys_ptrace'),
    148                 ('testTYPE', 'testTYPE', 'capability', 'sys_pacct'),
    149                 ('testTYPE', 'testTYPE', 'capability', 'sys_admin'),
    150                 ('testTYPE', 'testTYPE', 'capability', 'sys_boot'),
    151                 ('testTYPE', 'testTYPE', 'capability', 'sys_nice'),
    152                 ('testTYPE', 'testTYPE', 'capability', 'sys_resource'),
    153                 ('testTYPE', 'testTYPE', 'capability', 'sys_time'),
    154                 ('testTYPE', 'testTYPE', 'capability', 'sys_tty_config'),
    155                 ('testTYPE', 'testTYPE', 'capability', 'mknod'),
    156                 ('testTYPE', 'testTYPE', 'capability', 'lease'),
    157                 ('testTYPE', 'testTYPE', 'capability', 'audit_write'),
    158                 ('testTYPE', 'testTYPE', 'capability', 'audit_control'),
    159                 ('testTYPE', 'testTYPE', 'capability', 'setfcap') ] ]
    160 
    161 
    162 class SELinuxPolicyTests(unittest.TestCase):
    163 
    164 
    165     def setUp(self):
    166         self.test_policy = SELinuxPolicy()
    167         self.test_file = open(policy_file_name, 'r')
    168         self.test_policy.types = types
    169         self.test_policy.attributes = attributes
    170         self.test_policy.common_classes = common_classes
    171         self.test_policy.classes = classes
    172         self.test_policy.allow_rules = allow_rules
    173         self.test_policy.neverallow_rules = neverallow_rules
    174         return
    175 
    176     def testExpandAvcRule(self):
    177         #TODO: add more examples here to cover different cases
    178         expanded_allow_list = SELinux_CTS.expand_avc_rule(self.test_policy, self.test_policy.allow_rules[0])
    179         for a in expected_final_allow_list[0]:
    180             self.failUnless(a in expanded_allow_list)
    181         expanded_neverallow_list = SELinux_CTS.expand_avc_rule(self.test_policy, self.test_policy.neverallow_rules[0])
    182         for n in expected_final_neverallow_list[0]:
    183             self.failUnless(n in expanded_neverallow_list)
    184 
    185     def testExpandBrackets(self):
    186         #test position without bracket:
    187         self.test_file.seek(279)
    188         self.failIf(SELinux_CTS.expand_brackets(self.test_file))
    189 
    190         #test position with bracket:
    191         self.test_file.seek(26123)
    192         self.failUnless(SELinux_CTS.expand_brackets(self.test_file) == " entrypoint read execute ")
    193 
    194         #test position with nested brackets:
    195         self.test_file.seek(26873)
    196         self.failUnless(SELinux_CTS.expand_brackets(self.test_file)
    197                == " dir   chr_file blk_file   file lnk_file sock_file fifo_file   ")
    198 
    199     def testGetAvcRuleComponent(self):
    200         #test against normal ('allow healthd healthd_exec:file ...)
    201         self.test_file.seek(26096)
    202         normal_src = { 'flags': { 'complement': False },
    203                 'set': set(['healthd']) }
    204         normal_tgt = { 'flags': { 'complement': False },
    205                 'set': set(['healthd_exec']) }
    206         normal_class = { 'flags': { 'complement': False },
    207                 'set': set(['file']) }
    208         normal_perm = { 'flags': { 'complement': False },
    209                 'set': set(['entrypoint', 'read', 'execute']) }
    210         self.failUnless(SELinux_CTS.get_avc_rule_component(self.test_file)
    211             == normal_src)
    212         self.failUnless(SELinux_CTS.get_avc_rule_component(self.test_file)
    213             == normal_tgt)
    214         c = SELinux_CTS.advance_past_whitespace(self.test_file)
    215         if c == ':':
    216             self.test_file.read(1)
    217         self.failUnless(SELinux_CTS.get_avc_rule_component(self.test_file)
    218             == normal_class)
    219         self.failUnless(SELinux_CTS.get_avc_rule_component(self.test_file)
    220             == normal_perm)
    221 
    222         #test against 'hard' ('init {fs_type  ...' )
    223         self.test_file.seek(26838)
    224         hard_src = { 'flags': { 'complement': False },
    225                 'set': set(['init']) }
    226         hard_tgt = { 'flags': { 'complement': False },
    227                 'set': set(['fs_type', 'dev_type', 'file_type']) }
    228         hard_class = { 'flags': { 'complement': False },
    229                 'set': set(['dir', 'chr_file', 'blk_file', 'file', 'lnk_file', 'sock_file', 'fifo_file']) }
    230         hard_perm = { 'flags': { 'complement': False },
    231                 'set': set(['relabelto']) }
    232         self.failUnless(SELinux_CTS.get_avc_rule_component(self.test_file)
    233             == hard_src)
    234         self.failUnless(SELinux_CTS.get_avc_rule_component(self.test_file)
    235             == hard_tgt)
    236         #mimic ':' check:
    237         c = SELinux_CTS.advance_past_whitespace(self.test_file)
    238         if c == ':':
    239             self.test_file.read(1)
    240         self.failUnless(SELinux_CTS.get_avc_rule_component(self.test_file)
    241             == hard_class)
    242         self.failUnless(SELinux_CTS.get_avc_rule_component(self.test_file)
    243             == hard_perm)
    244 
    245         #test against 'multi-line' ('init {fs_type  ...' )
    246         self.test_file.seek(26967)
    247         multi_src = { 'flags': { 'complement': False },
    248                 'set': set(['appdomain', '-unconfineddomain']) }
    249         multi_tgt = { 'flags': { 'complement': False },
    250                 'set': set(['audio_device', 'camera_device', 'dm_device', 'radio_device', 'gps_device', 'rpmsg_device']) }
    251         multi_class = { 'flags': { 'complement': False },
    252                 'set': set(['chr_file']) }
    253         multi_perm = { 'flags': { 'complement': False },
    254                 'set': set(['read', 'write']) }
    255         self.failUnless(SELinux_CTS.get_avc_rule_component(self.test_file)
    256             == multi_src)
    257         self.failUnless(SELinux_CTS.get_avc_rule_component(self.test_file)
    258             == multi_tgt)
    259         c = SELinux_CTS.advance_past_whitespace(self.test_file)
    260         if c == ':':
    261             self.test_file.read(1)
    262         self.failUnless(SELinux_CTS.get_avc_rule_component(self.test_file)
    263             == multi_class)
    264         self.failUnless(SELinux_CTS.get_avc_rule_component(self.test_file)
    265             == multi_perm)
    266 
    267         #test against 'complement'
    268         self.test_file.seek(26806)
    269         complement = { 'flags': { 'complement': True },
    270                 'set': set(['entrypoint', 'relabelto']) }
    271         self.failUnless(SELinux_CTS.get_avc_rule_component(self.test_file)
    272             == complement)
    273 
    274     def testGetLineType(self):
    275         self.failUnless(SELinux_CTS.get_line_type('type bluetooth, domain;')
    276                 == SELinux_CTS.TYPE)
    277         self.failUnless(SELinux_CTS.get_line_type('attribute unconfineddomain;')
    278                 == SELinux_CTS.ATTRIBUTE)
    279         self.failUnless(SELinux_CTS.get_line_type('typeattribute bluetooth appdomain;')
    280                 == SELinux_CTS.TYPEATTRIBUTE)
    281         self.failUnless(SELinux_CTS.get_line_type('class file')
    282                 == SELinux_CTS.CLASS)
    283         self.failUnless(SELinux_CTS.get_line_type('common file')
    284                 == SELinux_CTS.COMMON)
    285         self.failUnless(SELinux_CTS.get_line_type('allow healthd healthd_exec:file { entrypoint read execute };')
    286                 == SELinux_CTS.ALLOW_RULE)
    287         self.failUnless(SELinux_CTS.get_line_type('neverallow { appdomain -unconfineddomain -bluetooth } self:capability *;')
    288                 == SELinux_CTS.NEVERALLOW_RULE)
    289         self.failUnless(SELinux_CTS.get_line_type('# FLASK')
    290                 == SELinux_CTS.OTHER)
    291 
    292     def testIsMultiLine(self):
    293         self.failIf(SELinux_CTS.is_multi_line(SELinux_CTS.TYPE))
    294         self.failIf(SELinux_CTS.is_multi_line(SELinux_CTS.ATTRIBUTE))
    295         self.failIf(SELinux_CTS.is_multi_line(SELinux_CTS.TYPEATTRIBUTE))
    296         self.failUnless(SELinux_CTS.is_multi_line(SELinux_CTS.CLASS))
    297         self.failUnless(SELinux_CTS.is_multi_line(SELinux_CTS.COMMON))
    298         self.failUnless(SELinux_CTS.is_multi_line(SELinux_CTS.ALLOW_RULE))
    299         self.failUnless(SELinux_CTS.is_multi_line(SELinux_CTS.NEVERALLOW_RULE))
    300         self.failIf(SELinux_CTS.is_multi_line(SELinux_CTS.OTHER))
    301 
    302     def testProcessInheritsSegment(self):
    303         inherit_offset = 448 # needs changing if file changes
    304         self.test_file.seek(inherit_offset, 0)
    305         inherit_result = SELinux_CTS.process_inherits_segment(self.test_file)
    306         self.failUnless(inherit_result == 'file')
    307         return
    308 
    309     def testFromFileName(self):
    310         #using a special file, since the test_file has some lines which don't 'jive'
    311         clean_policy_file = 'policy_clean_test.conf'
    312         from_file_policy = SELinuxPolicy()
    313         from_file_policy.from_file_name(clean_policy_file)
    314         self.failUnless(from_file_policy.types == self.test_policy.types)
    315         self.failUnless(from_file_policy.attributes == self.test_policy.attributes)
    316         self.failUnless(from_file_policy.classes == self.test_policy.classes)
    317         self.failUnless(from_file_policy.common_classes == self.test_policy.common_classes)
    318         self.failUnless(from_file_policy.allow_rules == self.test_policy.allow_rules)
    319         self.failUnless(from_file_policy.neverallow_rules == self.test_policy.neverallow_rules)
    320 
    321     def testExpandPermissions(self):
    322         #test general case
    323         test_class_obj = 'file'
    324         general_set = set(['read', 'write', 'execute'])
    325         expanded_general_set = general_set
    326         self.failUnless(self.test_policy.expand_permissions(test_class_obj, general_set)
    327                 == general_set)
    328         star_set = set(['*'])
    329         expanded_star_set = self.test_policy.classes['file'] #everything in the class
    330         self.failUnless(self.test_policy.expand_permissions(test_class_obj, star_set)
    331                 == expanded_star_set)
    332         complement_set = set(['*', '-open'])
    333         expanded_complement_set = self.test_policy.classes['file'] - set(['open'])
    334         self.failUnless(self.test_policy.expand_permissions(test_class_obj, complement_set)
    335                 == expanded_complement_set)
    336 
    337     def testExpandTypes(self):
    338 
    339         #test general case and '-' handling
    340         test_source_set = set([
    341                 'domain',
    342                 '-bluetooth' ])
    343         expanded_test_source_set = set([
    344                 'healthd', 'testTYPE' ])
    345         self.failUnless(self.test_policy.expand_types(test_source_set) == expanded_test_source_set)
    346 
    347         #test '*' handling
    348         test_source_set = set([ '*' ])
    349         expanded_test_source_set = set([
    350                 'bluetooth', 'healthd', 'testTYPE' ])
    351         self.failUnless(self.test_policy.expand_types(test_source_set) == types)
    352         #test - handling
    353         test_source_set = set([
    354                 '*',
    355                 '-bluetooth'])
    356         expanded_test_source_set = set([
    357                 'healthd', 'healthd_exec', 'testTYPE' ])
    358         self.failUnless(self.test_policy.expand_types(test_source_set) == expanded_test_source_set)
    359 
    360     def testProcessAttributeLine(self):
    361         attribute_policy = SELinuxPolicy()
    362         #test with 'normal input'
    363         test_normal_string = 'attribute TEST_att;'
    364         test_attribute = 'TEST_att'
    365         attribute_policy.process_attribute_line(test_normal_string)
    366         self.failUnless( test_attribute in attribute_policy.attributes)
    367         #TODO: test on bogus inputs
    368 
    369     def testProcessClassLine(self):
    370         class_policy = SELinuxPolicy()
    371         #offsets need changing if test file changes
    372         common_offset  = 279
    373         class_initial_offset  = 212
    374         class_perm_offset = 437
    375         self.test_file.seek(common_offset, 0)
    376         line = self.test_file.readline()
    377         class_policy.process_common_line(line, self.test_file)
    378         self.test_file.seek(class_initial_offset, 0)
    379         line = self.test_file.readline()
    380         class_policy.process_class_line(line, self.test_file)
    381         self.failUnless('file' in class_policy.classes)
    382         self.test_file.seek(class_perm_offset, 0)
    383         line = self.test_file.readline()
    384         class_policy.process_class_line(line, self.test_file)
    385         self.failUnless(class_policy.classes['file'] == classes['file'])
    386 
    387     def testProcessCommonLine(self):
    388         common_policy = SELinuxPolicy()
    389         common_offset  = 279 # needs changing if file changes
    390         self.test_file.seek(common_offset, 0)
    391         line = self.test_file.readline()
    392         common_policy.process_common_line(line, self.test_file)
    393         self.failUnless('file' in common_policy.common_classes )
    394         self.failUnless(common_policy.common_classes['file'] == common_classes['file'])
    395 
    396     def testProcessAvcRuleLine(self):
    397         avc_policy = SELinuxPolicy()
    398         allow_offset  =  26091 # needs changing if file changes
    399         neverallow_offset  = 26311  # needs changing if file changes
    400         self.test_file.seek(allow_offset, 0)
    401         line = self.test_file.readline()
    402         avc_policy.process_avc_rule_line(line, self.test_file)
    403         self.failUnless(avc_policy.allow_rules[0] == allow_rules[0] ) # always '0'?
    404         self.test_file.seek(neverallow_offset, 0)
    405         line = self.test_file.readline()
    406         avc_policy.process_avc_rule_line(line, self.test_file)
    407         self.failUnless(avc_policy.neverallow_rules[0] == neverallow_rules[0] ) # always '0'?
    408 
    409     def testProcessTypeLine(self):
    410         type_policy = SELinuxPolicy()
    411         test_normal_string = 'type TEST_type, TEST_att1, TEST_att2;'
    412         test_type = 'TEST_type'
    413         test_atts = ['TEST_att1', 'TEST_att2']
    414         #test with 'normal input'
    415         type_policy.process_type_line(test_normal_string)
    416         self.failUnless(test_type in type_policy.types)
    417         for a in test_atts:
    418             self.failUnless(a in type_policy.attributes)
    419             self.failUnless(test_type in type_policy.attributes[a])
    420         #TODO: test with domain only, no attributes
    421         # and test on bogus inputs
    422 
    423     def testProcessTypeattributeLine(self):
    424         typ_att_policy = SELinuxPolicy()
    425         test_normal_string = 'typeattribute TEST_type TEST_att1, TEST_att2;'
    426         test_type = 'TEST_type'
    427         test_atts = ['TEST_att1', 'TEST_att2']
    428         #test with 'normal input' (type should already be declared)
    429         typ_att_policy.process_type_line('type ' + test_type + ';')
    430         typ_att_policy.process_typeattribute_line(test_normal_string)
    431         self.failUnless(test_type in typ_att_policy.types)
    432         for a in test_atts:
    433             self.failUnless(a in typ_att_policy.attributes)
    434             self.failUnless(test_type in typ_att_policy.attributes[a])
    435         #TODO: test with domain only, no attributes
    436         # and test on bogus inputs
    437 
    438 def main():
    439     unittest.main()
    440 
    441 if __name__ == '__main__':
    442     main()
    443