• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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())