1#!/usr/bin/env python3 2# -*- coding: utf-8 -*- 3 4# 5# Copyright (c) 2023 Huawei Device Co., Ltd. 6# Licensed under the Apache License, Version 2.0 (the "License"); 7# you may not use this file except in compliance with the License. 8# You may obtain a copy of the License at 9# 10# http://www.apache.org/licenses/LICENSE-2.0 11# 12# Unless required by applicable law or agreed to in writing, software 13# distributed under the License is distributed on an "AS IS" BASIS, 14# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15# See the License for the specific language governing permissions and 16# limitations under the License. 17# 18 19import argparse 20import sys 21import os 22import stat 23import generate_code_from_policy as gen_policy 24 25 26def parse_line(fp, arch_nr): 27 arch_id_map = { 28 '40000028': 'arm', 29 'c00000b7': 'arm64' 30 } 31 for line in fp: 32 line = line.strip() 33 if 'audit' not in line or 'type=1326' not in line: 34 continue 35 36 pos = line.find(' syscall=') 37 arch_id = line[line.find('arch=') + 5 : pos] 38 syscall, _ = gen_policy.str_convert_to_int(line[pos + 9: line.find(' compat')]) 39 arch_nr.get(arch_id_map.get(arch_id)).add(syscall) 40 41 42def get_item_content(name_nr_table, arch_nr_table): 43 content = '@allowList\n' 44 syscall_name_dict = { 45 'arm': list(), 46 'arm64': list() 47 } 48 supported_architecture = ['arm64', 'arm'] 49 for arch in supported_architecture: 50 for nr in sorted(list(arch_nr_table.get(arch))): 51 syscall_name = name_nr_table.get(arch).get(nr) 52 if not syscall_name: 53 raise ValueError('nr is not ilegal') 54 syscall_name_dict.get(arch).append(syscall_name) 55 56 for func_name in syscall_name_dict.get('arm64'): 57 if func_name in syscall_name_dict.get('arm'): 58 content = '{}{};all\n'.format(content, func_name) 59 syscall_name_dict.get('arm').remove(func_name) 60 else: 61 content = '{}{};arm64\n'.format(content, func_name) 62 if syscall_name_dict.get('arm'): 63 content = '{}{};arm\n'.format(content, ';arm\n'.join( 64 [func_name for func_name in syscall_name_dict.get('arm')])) 65 66 return content 67 68 69def gen_output_file(filter_name, content): 70 flags = os.O_WRONLY | os.O_CREAT | os.O_TRUNC 71 modes = stat.S_IWUSR | stat.S_IRUSR | stat.S_IWGRP | stat.S_IRGRP 72 with os.fdopen(os.open(filter_name + '.seccomp.policy', flags, modes), 'w') as output_file: 73 output_file.write(content) 74 75 76def parse_file(file_name, arch_nr): 77 with open(file_name) as f: 78 parse_line(f, arch_nr) 79 80 81def converse_fuction_name_nr(dict_dst, dict_src): 82 for arch in dict_src.keys(): 83 dict_dst.update({arch: dict()}) 84 85 for arch in dict_src.keys(): 86 for key, value in dict_src.get(arch).items(): 87 dict_dst.get(arch).update({value: key}) 88 return dict_dst 89 90 91def parse_audit_log_to_policy(args): 92 file_list = extract_file_from_path(args.src_path) 93 function_name_nr_table_dict_tmp = {} 94 function_name_nr_table_dict = {} 95 arch_nr = { 96 'arm': set(), 97 'arm64': set() 98 } 99 for file_name in file_list: 100 file_name_tmp = file_name.split('/')[-1] 101 if not file_name_tmp.lower().startswith('libsyscall_to_nr_'): 102 continue 103 function_name_nr_table_dict_tmp = gen_policy.gen_syscall_nr_table(file_name, function_name_nr_table_dict_tmp) 104 105 converse_fuction_name_nr(function_name_nr_table_dict, function_name_nr_table_dict_tmp) 106 107 for file_name in file_list: 108 if file_name.lower().endswith('.audit.log'): 109 parse_file(file_name, arch_nr) 110 111 content = get_item_content(function_name_nr_table_dict, arch_nr) 112 gen_output_file(args.filter_name, content) 113 114 115def extract_file_from_path(dir_path): 116 file_list = [] 117 for path in dir_path: 118 if path[-1] == '/': 119 print('input dir path can not end with /') 120 return [] 121 122 if os.path.isdir(path): 123 # get file list 124 file_list_tmp = os.listdir(path) 125 file_list += ['{}/{}'.format(path, item) for item in file_list_tmp] 126 127 return file_list 128 129 130def main(): 131 parser = argparse.ArgumentParser( 132 description='Generates a seccomp-bpf policy') 133 parser.add_argument('--src-path', action='append', 134 help='path to syscall to nr files') 135 parser.add_argument('--filter-name', type=str, 136 help=('The input files\n')) 137 138 139 args = parser.parse_args() 140 parse_audit_log_to_policy(args) 141 142 143if __name__ == '__main__': 144 sys.exit(main())