#!/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()