1c1ed15f1Sopenharmony_ci#!/usr/bin/env python 2c1ed15f1Sopenharmony_ci# coding: utf-8 3c1ed15f1Sopenharmony_ci 4c1ed15f1Sopenharmony_ci""" 5c1ed15f1Sopenharmony_ciCopyright (c) 2024 Huawei Device Co., Ltd. 6c1ed15f1Sopenharmony_ciLicensed under the Apache License, Version 2.0 (the "License"); 7c1ed15f1Sopenharmony_ciyou may not use this file except in compliance with the License. 8c1ed15f1Sopenharmony_ciYou may obtain a copy of the License at 9c1ed15f1Sopenharmony_ci 10c1ed15f1Sopenharmony_ci http://www.apache.org/licenses/LICENSE-2.0 11c1ed15f1Sopenharmony_ci 12c1ed15f1Sopenharmony_ciUnless required by applicable law or agreed to in writing, software 13c1ed15f1Sopenharmony_cidistributed under the License is distributed on an "AS IS" BASIS, 14c1ed15f1Sopenharmony_ciWITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15c1ed15f1Sopenharmony_ciSee the License for the specific language governing permissions and 16c1ed15f1Sopenharmony_cilimitations under the License. 17c1ed15f1Sopenharmony_ci 18c1ed15f1Sopenharmony_ci""" 19c1ed15f1Sopenharmony_ci 20c1ed15f1Sopenharmony_ciimport argparse 21c1ed15f1Sopenharmony_ciimport os 22c1ed15f1Sopenharmony_cifrom check_common import read_json_file, traverse_file_in_each_type 23c1ed15f1Sopenharmony_ci 24c1ed15f1Sopenharmony_ciWHITELIST_FILE_NAME = "ioctl_xperm_whitelist.json" 25c1ed15f1Sopenharmony_ci 26c1ed15f1Sopenharmony_ciALLOW_TCONTEXT_CLASS_LIST = ["data_log_sanitizer_file file", "proc_attr dir", "self dir", "self fifo_file", 27c1ed15f1Sopenharmony_ci "self file", "self lnk_file", "self unix_stream_socket"] 28c1ed15f1Sopenharmony_ci 29c1ed15f1Sopenharmony_ci 30c1ed15f1Sopenharmony_ciclass PolicyDb(object): 31c1ed15f1Sopenharmony_ci def __init__(self, allowx_set, allow_set, typetransition_set): 32c1ed15f1Sopenharmony_ci self.allowx_set = allowx_set 33c1ed15f1Sopenharmony_ci self.allow_set = allow_set 34c1ed15f1Sopenharmony_ci self.typetransition_set = typetransition_set 35c1ed15f1Sopenharmony_ci 36c1ed15f1Sopenharmony_ci 37c1ed15f1Sopenharmony_cidef simplify_string(string): 38c1ed15f1Sopenharmony_ci return string.strip().replace('(', '').replace(')', '') 39c1ed15f1Sopenharmony_ci 40c1ed15f1Sopenharmony_ci 41c1ed15f1Sopenharmony_cidef split_allow_rule(elem_list, allow_set, allowx_set): 42c1ed15f1Sopenharmony_ci if len(elem_list) < 5: 43c1ed15f1Sopenharmony_ci print("not an allow/allowx rule: {}".format(elem_list)) 44c1ed15f1Sopenharmony_ci return 45c1ed15f1Sopenharmony_ci rulename = elem_list[0] 46c1ed15f1Sopenharmony_ci scontext = elem_list[1] 47c1ed15f1Sopenharmony_ci tcontext = elem_list[2] 48c1ed15f1Sopenharmony_ci tclass = elem_list[3] 49c1ed15f1Sopenharmony_ci if rulename == 'allow' and 'ioctl' in elem_list[4:]: 50c1ed15f1Sopenharmony_ci keycontent = f'{scontext} {tcontext} {tclass}' 51c1ed15f1Sopenharmony_ci allow_set.add(keycontent) 52c1ed15f1Sopenharmony_ci if rulename == 'allowx' and 'ioctl' == tclass: 53c1ed15f1Sopenharmony_ci keycontent = f'{scontext} {tcontext} {elem_list[4]}' 54c1ed15f1Sopenharmony_ci allowx_set.add(keycontent) 55c1ed15f1Sopenharmony_ci 56c1ed15f1Sopenharmony_ci 57c1ed15f1Sopenharmony_cidef split_typetransition(elem_list, typetransition_set): 58c1ed15f1Sopenharmony_ci if len(elem_list) < 5: 59c1ed15f1Sopenharmony_ci print("not a typetransition rule: {}".format(elem_list)) 60c1ed15f1Sopenharmony_ci return 61c1ed15f1Sopenharmony_ci rulename = elem_list[0] 62c1ed15f1Sopenharmony_ci source_t = elem_list[1] 63c1ed15f1Sopenharmony_ci target_t = elem_list[2] 64c1ed15f1Sopenharmony_ci tclass = elem_list[3] 65c1ed15f1Sopenharmony_ci default_t = elem_list[4] 66c1ed15f1Sopenharmony_ci if tclass == 'process': 67c1ed15f1Sopenharmony_ci keycontent = f'{source_t} {target_t} file' 68c1ed15f1Sopenharmony_ci typetransition_set.add(keycontent) 69c1ed15f1Sopenharmony_ci 70c1ed15f1Sopenharmony_ci 71c1ed15f1Sopenharmony_cidef deal_with_allow(cil_file, allow_set, allowx_set, typetransition_set): 72c1ed15f1Sopenharmony_ci with open(cil_file, 'r', encoding='utf-8') as cil_read: 73c1ed15f1Sopenharmony_ci for line in cil_read: 74c1ed15f1Sopenharmony_ci if line.startswith('(typetransition '): 75c1ed15f1Sopenharmony_ci # (typetransition A B process C) 76c1ed15f1Sopenharmony_ci sub_string = simplify_string(line) 77c1ed15f1Sopenharmony_ci elem_list = sub_string.split(' ') 78c1ed15f1Sopenharmony_ci split_typetransition(elem_list, typetransition_set) 79c1ed15f1Sopenharmony_ci 80c1ed15f1Sopenharmony_ci if line.startswith('(allow ') or line.startswith('(allowx '): 81c1ed15f1Sopenharmony_ci sub_string = simplify_string(line) 82c1ed15f1Sopenharmony_ci elem_list = sub_string.split(' ') 83c1ed15f1Sopenharmony_ci # (allow A B (file (ioctl x x x))) 84c1ed15f1Sopenharmony_ci # (allowx A B (ioctl file (x x x))) 85c1ed15f1Sopenharmony_ci split_allow_rule(elem_list, allow_set, allowx_set) 86c1ed15f1Sopenharmony_ci 87c1ed15f1Sopenharmony_ci 88c1ed15f1Sopenharmony_cidef generate_database(args, with_developer): 89c1ed15f1Sopenharmony_ci allowx_set = set() 90c1ed15f1Sopenharmony_ci allow_set = set() 91c1ed15f1Sopenharmony_ci typetransition_set = set() 92c1ed15f1Sopenharmony_ci if with_developer: 93c1ed15f1Sopenharmony_ci deal_with_allow(args.developer_cil_file, allow_set, allowx_set, typetransition_set) 94c1ed15f1Sopenharmony_ci else: 95c1ed15f1Sopenharmony_ci deal_with_allow(args.cil_file, allow_set, allowx_set, typetransition_set) 96c1ed15f1Sopenharmony_ci 97c1ed15f1Sopenharmony_ci return PolicyDb(allowx_set, allow_set, typetransition_set) 98c1ed15f1Sopenharmony_ci 99c1ed15f1Sopenharmony_ci 100c1ed15f1Sopenharmony_cidef get_whitelist(args, with_developer): 101c1ed15f1Sopenharmony_ci whitelist_file_list = traverse_file_in_each_type(args.policy_dir_list, WHITELIST_FILE_NAME) 102c1ed15f1Sopenharmony_ci contexts_list = [] 103c1ed15f1Sopenharmony_ci for path in whitelist_file_list: 104c1ed15f1Sopenharmony_ci white_list = read_json_file(path).get('whitelist') 105c1ed15f1Sopenharmony_ci contexts_list.extend(white_list.get('user')) 106c1ed15f1Sopenharmony_ci if with_developer: 107c1ed15f1Sopenharmony_ci contexts_list.extend(white_list.get('developer')) 108c1ed15f1Sopenharmony_ci return contexts_list 109c1ed15f1Sopenharmony_ci 110c1ed15f1Sopenharmony_ci 111c1ed15f1Sopenharmony_cidef check(args, with_developer): 112c1ed15f1Sopenharmony_ci policy_db = generate_database(args, with_developer) 113c1ed15f1Sopenharmony_ci contexts_list = get_whitelist(args, with_developer) 114c1ed15f1Sopenharmony_ci diff_set = policy_db.allow_set - policy_db.allowx_set - policy_db.typetransition_set - set(contexts_list) 115c1ed15f1Sopenharmony_ci notallow = list() 116c1ed15f1Sopenharmony_ci for diff in diff_set: 117c1ed15f1Sopenharmony_ci if not (diff.endswith(tuple(ALLOW_TCONTEXT_CLASS_LIST))) : 118c1ed15f1Sopenharmony_ci notallow.append(diff) 119c1ed15f1Sopenharmony_ci 120c1ed15f1Sopenharmony_ci if len(notallow) > 0 : 121c1ed15f1Sopenharmony_ci print('check ioctl rule in {} mode failed.'.format("developer" if with_developer else "user")) 122c1ed15f1Sopenharmony_ci print('violation list (allow scontext tcontext:tclass ioctl)') 123c1ed15f1Sopenharmony_ci for e in sorted(notallow): 124c1ed15f1Sopenharmony_ci elem_list = e.split(' ') 125c1ed15f1Sopenharmony_ci print('\tallow {} ioctl;'.format(elem_list[0] + ' ' + elem_list[1] + ':' + elem_list[2])) 126c1ed15f1Sopenharmony_ci print('please add "allowxperm" rule based on the above list.') 127c1ed15f1Sopenharmony_ci return len(notallow) > 0 128c1ed15f1Sopenharmony_ci 129c1ed15f1Sopenharmony_ci 130c1ed15f1Sopenharmony_cidef parse_args(): 131c1ed15f1Sopenharmony_ci parser = argparse.ArgumentParser() 132c1ed15f1Sopenharmony_ci parser.add_argument('--cil_file', help='the cil file path', required=True) 133c1ed15f1Sopenharmony_ci parser.add_argument('--developer_cil_file', help='the developer cil file path', required=True) 134c1ed15f1Sopenharmony_ci parser.add_argument('--policy-dir-list', help='policy dirs need to be included', required=True) 135c1ed15f1Sopenharmony_ci 136c1ed15f1Sopenharmony_ci return parser.parse_args() 137c1ed15f1Sopenharmony_ci 138c1ed15f1Sopenharmony_ci 139c1ed15f1Sopenharmony_ciif __name__ == '__main__': 140c1ed15f1Sopenharmony_ci input_args = parse_args() 141c1ed15f1Sopenharmony_ci print("check xperm input_args: {}".format(input_args)) 142c1ed15f1Sopenharmony_ci result = check(input_args, False) 143c1ed15f1Sopenharmony_ci if result: 144c1ed15f1Sopenharmony_ci raise Exception(-1) 145c1ed15f1Sopenharmony_ci result = check(input_args, True) 146c1ed15f1Sopenharmony_ci if result: 147c1ed15f1Sopenharmony_ci raise Exception(-1) 148c1ed15f1Sopenharmony_ci 149