1d9f0492fSopenharmony_ci#!/usr/bin/env python3
2d9f0492fSopenharmony_ci# -*- coding: utf-8 -*-
3d9f0492fSopenharmony_ci
4d9f0492fSopenharmony_ci#
5d9f0492fSopenharmony_ci# Copyright (c) 2023 Huawei Device Co., Ltd.
6d9f0492fSopenharmony_ci# Licensed under the Apache License, Version 2.0 (the "License");
7d9f0492fSopenharmony_ci# you may not use this file except in compliance with the License.
8d9f0492fSopenharmony_ci# You may obtain a copy of the License at
9d9f0492fSopenharmony_ci#
10d9f0492fSopenharmony_ci#     http://www.apache.org/licenses/LICENSE-2.0
11d9f0492fSopenharmony_ci#
12d9f0492fSopenharmony_ci# Unless required by applicable law or agreed to in writing, software
13d9f0492fSopenharmony_ci# distributed under the License is distributed on an "AS IS" BASIS,
14d9f0492fSopenharmony_ci# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15d9f0492fSopenharmony_ci# See the License for the specific language governing permissions and
16d9f0492fSopenharmony_ci# limitations under the License.
17d9f0492fSopenharmony_ci#
18d9f0492fSopenharmony_ci
19d9f0492fSopenharmony_ciimport sys
20d9f0492fSopenharmony_ciimport argparse
21d9f0492fSopenharmony_ciimport audit_log_analysis as audit_policy
22d9f0492fSopenharmony_ciimport generate_code_from_policy as gen_policy
23d9f0492fSopenharmony_ci
24d9f0492fSopenharmony_ci
25d9f0492fSopenharmony_ciclass MergePolicy:
26d9f0492fSopenharmony_ci    def __init__(self):
27d9f0492fSopenharmony_ci        self.cur_parse_item = ''
28d9f0492fSopenharmony_ci        self.arches = set()
29d9f0492fSopenharmony_ci        self.seccomp_policy_param = dict()
30d9f0492fSopenharmony_ci
31d9f0492fSopenharmony_ci    @staticmethod
32d9f0492fSopenharmony_ci    def get_item_content(name_nr_table, item_str, itme_dict):
33d9f0492fSopenharmony_ci        syscall_name_dict = {}
34d9f0492fSopenharmony_ci        flag = False
35d9f0492fSopenharmony_ci        for arch in gen_policy.supported_architecture:
36d9f0492fSopenharmony_ci            func_name_to_nr = dict()
37d9f0492fSopenharmony_ci            for item in itme_dict.get(arch):
38d9f0492fSopenharmony_ci                if ':' in item:
39d9f0492fSopenharmony_ci                    func_name = item[:item.find(':')].strip()
40d9f0492fSopenharmony_ci                else:
41d9f0492fSopenharmony_ci                    func_name = item
42d9f0492fSopenharmony_ci                func_name_to_nr.update({item: name_nr_table.get(arch).get(func_name)})
43d9f0492fSopenharmony_ci            func_name_to_nr_list = sorted(func_name_to_nr.items(), key=lambda x : x[1])
44d9f0492fSopenharmony_ci
45d9f0492fSopenharmony_ci            syscall_name_dict.update({arch: func_name_to_nr_list})
46d9f0492fSopenharmony_ci        for arch in gen_policy.supported_architecture:
47d9f0492fSopenharmony_ci            if syscall_name_dict.get(arch):
48d9f0492fSopenharmony_ci                flag = True
49d9f0492fSopenharmony_ci        if not flag:
50d9f0492fSopenharmony_ci            return ''
51d9f0492fSopenharmony_ci        content = '{}\n'.format(item_str)
52d9f0492fSopenharmony_ci
53d9f0492fSopenharmony_ci        for func_name, _ in syscall_name_dict.get('arm64'):
54d9f0492fSopenharmony_ci            flag = False
55d9f0492fSopenharmony_ci            for func_name_arm, nr_arm in syscall_name_dict.get('arm'):
56d9f0492fSopenharmony_ci                if func_name == func_name_arm:
57d9f0492fSopenharmony_ci                    content = '{}{};all\n'.format(content, func_name)
58d9f0492fSopenharmony_ci                    syscall_name_dict.get('arm').remove((func_name, nr_arm))
59d9f0492fSopenharmony_ci                    flag = True
60d9f0492fSopenharmony_ci                    break
61d9f0492fSopenharmony_ci            if not flag:
62d9f0492fSopenharmony_ci                content = '{}{};arm64\n'.format(content, func_name)
63d9f0492fSopenharmony_ci        if (syscall_name_dict.get('arm')):
64d9f0492fSopenharmony_ci            content = '{}{};arm\n'.format(content, ';arm\n'.join(
65d9f0492fSopenharmony_ci                      [func_name for func_name, _ in syscall_name_dict.get('arm')]))
66d9f0492fSopenharmony_ci        if (syscall_name_dict.get('riscv64')):
67d9f0492fSopenharmony_ci            content = '{}{};riscv64\n'.format(content, ';riscv64\n'.join(
68d9f0492fSopenharmony_ci                      [func_name for func_name, _ in syscall_name_dict.get('riscv64')]))
69d9f0492fSopenharmony_ci        return content
70d9f0492fSopenharmony_ci
71d9f0492fSopenharmony_ci    def update_parse_item(self, line):
72d9f0492fSopenharmony_ci        item = line[1:]
73d9f0492fSopenharmony_ci        if item in gen_policy.supported_parse_item:
74d9f0492fSopenharmony_ci            self.cur_parse_item = item
75d9f0492fSopenharmony_ci            print('start deal with {}'.format(self.cur_parse_item))
76d9f0492fSopenharmony_ci
77d9f0492fSopenharmony_ci    def parse_line(self, line):
78d9f0492fSopenharmony_ci        if not self.cur_parse_item :
79d9f0492fSopenharmony_ci            return
80d9f0492fSopenharmony_ci        line = line.replace(' ', '')
81d9f0492fSopenharmony_ci        pos = line.rfind(';')
82d9f0492fSopenharmony_ci        if pos < 0:
83d9f0492fSopenharmony_ci            for arch in self.arches:
84d9f0492fSopenharmony_ci                self.seccomp_policy_param.get(arch).value_function.get(self.cur_parse_item)(line)
85d9f0492fSopenharmony_ci        else:
86d9f0492fSopenharmony_ci            arches = line[pos + 1:].split(',')
87d9f0492fSopenharmony_ci            if arches[0] == 'all':
88d9f0492fSopenharmony_ci                arches = gen_policy.supported_architecture
89d9f0492fSopenharmony_ci            for arch in arches:
90d9f0492fSopenharmony_ci                self.seccomp_policy_param.get(arch).value_function.get(self.cur_parse_item)(line[:pos])
91d9f0492fSopenharmony_ci
92d9f0492fSopenharmony_ci
93d9f0492fSopenharmony_ci    def parse_open_file(self, fp):
94d9f0492fSopenharmony_ci        for line in fp:
95d9f0492fSopenharmony_ci            line = line.strip()
96d9f0492fSopenharmony_ci            if not line:
97d9f0492fSopenharmony_ci                continue
98d9f0492fSopenharmony_ci            if line[0] == '#':
99d9f0492fSopenharmony_ci                continue
100d9f0492fSopenharmony_ci            if line[0] == '@':
101d9f0492fSopenharmony_ci                self.update_parse_item(line)
102d9f0492fSopenharmony_ci                continue
103d9f0492fSopenharmony_ci            if line[0] != '@' and self.cur_parse_item == '':
104d9f0492fSopenharmony_ci                continue
105d9f0492fSopenharmony_ci            self.parse_line(line)
106d9f0492fSopenharmony_ci
107d9f0492fSopenharmony_ci    def parse_file(self, file_path):
108d9f0492fSopenharmony_ci        with open(file_path) as fp:
109d9f0492fSopenharmony_ci            self.parse_open_file(fp)
110d9f0492fSopenharmony_ci
111d9f0492fSopenharmony_ci    def merge_policy(self, args):
112d9f0492fSopenharmony_ci        function_name_nr_table_dict = {}
113d9f0492fSopenharmony_ci        for file_name in args.src_files:
114d9f0492fSopenharmony_ci            file_name_tmp = file_name.split('/')[-1]
115d9f0492fSopenharmony_ci            if not file_name_tmp.lower().startswith('libsyscall_to_nr_'):
116d9f0492fSopenharmony_ci                continue
117d9f0492fSopenharmony_ci            gen_policy.gen_syscall_nr_table(file_name, function_name_nr_table_dict)
118d9f0492fSopenharmony_ci
119d9f0492fSopenharmony_ci        for arch in gen_policy.supported_architecture:
120d9f0492fSopenharmony_ci            self.seccomp_policy_param.update(\
121d9f0492fSopenharmony_ci                {arch: gen_policy.SeccompPolicyParam(arch, function_name_nr_table_dict.get(arch))})
122d9f0492fSopenharmony_ci
123d9f0492fSopenharmony_ci        for file_name in args.src_files:
124d9f0492fSopenharmony_ci            if file_name.lower().endswith('.policy'):
125d9f0492fSopenharmony_ci                self.parse_file(file_name)
126d9f0492fSopenharmony_ci
127d9f0492fSopenharmony_ci        dict_priority = dict()
128d9f0492fSopenharmony_ci        dict_allow_list = dict()
129d9f0492fSopenharmony_ci        dict_priority_with_args = dict()
130d9f0492fSopenharmony_ci        dict_allow_list_with_args = dict()
131d9f0492fSopenharmony_ci        dict_blocklist = dict()
132d9f0492fSopenharmony_ci
133d9f0492fSopenharmony_ci        for arch in gen_policy.supported_architecture:
134d9f0492fSopenharmony_ci            dict_priority.update({arch: self.seccomp_policy_param.get(arch).priority})
135d9f0492fSopenharmony_ci            dict_allow_list.update({arch: self.seccomp_policy_param.get(arch).allow_list})
136d9f0492fSopenharmony_ci            dict_priority_with_args.update({arch: self.seccomp_policy_param.get(arch).priority_with_args})
137d9f0492fSopenharmony_ci            dict_allow_list_with_args.update({arch: self.seccomp_policy_param.get(arch).allow_list_with_args})
138d9f0492fSopenharmony_ci            dict_blocklist.update({arch: self.seccomp_policy_param.get(arch).blocklist})
139d9f0492fSopenharmony_ci
140d9f0492fSopenharmony_ci        content = self.get_item_content(function_name_nr_table_dict, "@priority", dict_priority)
141d9f0492fSopenharmony_ci        content += self.get_item_content(function_name_nr_table_dict, "@allowList", dict_allow_list)
142d9f0492fSopenharmony_ci        content += self.get_item_content(function_name_nr_table_dict, "@priorityWithArgs", dict_priority_with_args)
143d9f0492fSopenharmony_ci        content += self.get_item_content(function_name_nr_table_dict, "@allowListWithArgs", dict_allow_list_with_args)
144d9f0492fSopenharmony_ci        content += self.get_item_content(function_name_nr_table_dict, "@blockList", dict_blocklist)
145d9f0492fSopenharmony_ci        audit_policy.gen_output_file(args.filter_name, content)
146d9f0492fSopenharmony_ci
147d9f0492fSopenharmony_ci
148d9f0492fSopenharmony_cidef main():
149d9f0492fSopenharmony_ci    parser = argparse.ArgumentParser(
150d9f0492fSopenharmony_ci      description='Generates a seccomp-bpf policy')
151d9f0492fSopenharmony_ci    parser.add_argument('--src-files', type=str, action='append',
152d9f0492fSopenharmony_ci                        help=('input libsyscall_to_nr files and policy filse\n'))
153d9f0492fSopenharmony_ci
154d9f0492fSopenharmony_ci    parser.add_argument('--filter-name', type=str,
155d9f0492fSopenharmony_ci                        help='Name of seccomp bpf array generated by this script')
156d9f0492fSopenharmony_ci
157d9f0492fSopenharmony_ci    args = parser.parse_args()
158d9f0492fSopenharmony_ci
159d9f0492fSopenharmony_ci    generator = MergePolicy()
160d9f0492fSopenharmony_ci    generator.merge_policy(args)
161d9f0492fSopenharmony_ci
162d9f0492fSopenharmony_ci
163d9f0492fSopenharmony_ciif __name__ == '__main__':
164d9f0492fSopenharmony_ci    sys.exit(main())
165