• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1#!/usr/bin/env python
2# coding: utf-8
3
4"""
5Copyright (c) 2021-2022 Huawei Device Co., Ltd.
6Licensed under the Apache License, Version 2.0 (the "License");
7you may not use this file except in compliance with the License.
8You may obtain a copy of the License at
9
10    http://www.apache.org/licenses/LICENSE-2.0
11
12Unless required by applicable law or agreed to in writing, software
13distributed under the License is distributed on an "AS IS" BASIS,
14WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15See the License for the specific language governing permissions and
16limitations under the License.
17
18"""
19
20import os
21import argparse
22import re
23import shutil
24import subprocess
25from collections import defaultdict
26
27
28def parse_args():
29    parser = argparse.ArgumentParser()
30    parser.add_argument(
31        '--dst-dir', help='the output dest path', required=True)
32    parser.add_argument('--tool-path',
33                        help='the sefcontext_compile bin path', required=True)
34    parser.add_argument('--policy-file',
35                        help='the policy.31 file', required=True)
36    parser.add_argument('--source-root-dir',
37                        help='prj root path', required=True)
38    parser.add_argument('--policy_dir_list',
39                        help='policy dirs need to be included', required=True)
40    return parser.parse_args()
41
42
43def run_command(in_cmd):
44    cmdstr = " ".join(in_cmd)
45    ret = subprocess.run(cmdstr, shell=True).returncode
46    if ret != 0:
47        raise Exception(ret)
48
49
50def traverse_folder_in_type(search_dir_list, file_suffix):
51    """
52    for special folder search_dir, find all files endwith file_suffix.
53    :param search_dir: path to search
54    :param file_suffix: postfix of file name
55    :return: file list
56    """
57
58    policy_file_list = []
59    for item in search_dir_list:
60        for root, _, files in os.walk(item):
61            for each_file in files:
62                file_name = os.path.basename(each_file)
63                if file_name == file_suffix:
64                    policy_file_list.append(os.path.join(root, each_file))
65    policy_file_list.sort()
66    return " ".join(str(x) for x in policy_file_list)
67
68
69def combine_contexts_file(file_contexts_list, combined_file_contexts):
70    cat_cmd = ["cat",
71               file_contexts_list,
72               ">", combined_file_contexts + "_tmp"]
73    run_command(cat_cmd)
74
75    grep_cmd = ["grep -v ^#",
76                combined_file_contexts + "_tmp",
77                "| grep -v ^$",
78                ">", combined_file_contexts]
79    run_command(grep_cmd)
80
81
82def check_redefinition(contexts_file):
83    type_hash = defaultdict(list)
84    err = 0
85    with open(contexts_file, 'r') as contexts_read:
86        pattern = re.compile(r'(\S+)\s+u:object_r:\S+:s0')
87        line_index = 0
88        for line in contexts_read:
89            line_ = line.lstrip()
90            line_index += 1
91            if line_.startswith('#') or line_.strip() == '':
92                continue
93            match = pattern.match(line_)
94            if match:
95                type_hash[match.group(1)].append(line_index)
96            else:
97                print(contexts_file + ":" +
98                      str(line_index) + " format check fail")
99                err = 1
100        contexts_read.close()
101    if err:
102        print("***********************************************************")
103        print("please check whether the format meets the following rules:")
104        print("[required format]: * u:object_r:*:s0")
105        print("***********************************************************")
106        raise Exception(err)
107    err = 0
108    for type_key in type_hash.keys():
109        if len(type_hash[type_key]) > 1:
110            err = 1
111            str_seq = (contexts_file, ":")
112            err_msg = "".join(str_seq)
113            for linenum in type_hash[type_key]:
114                str_seq = (err_msg, str(linenum), ":")
115                err_msg = "".join(str_seq)
116            str_seq = (err_msg, "'type ", str(type_key), " is redefinition'")
117            err_msg = "".join(str_seq)
118            print(err_msg)
119    if err:
120        raise Exception(err)
121
122
123def check_common_contexts(args, contexts_file):
124    """
125    check whether context used in contexts_file is defined in policy.31.
126    :param args:
127    :param contexts_file: path of contexts file
128    :return:
129    """
130    check_redefinition(contexts_file)
131
132    check_cmd = [os.path.join(args.tool_path, "sefcontext_compile"),
133                 "-o", contexts_file + ".bin",
134                 "-p", args.policy_file,
135                 contexts_file]
136    run_command(check_cmd)
137    if os.path.exists(contexts_file + ".bin"):
138        os.unlink(contexts_file + ".bin")
139
140
141def check_sehap_contexts(args, contexts_file, domain):
142    """
143    check domain or type defined in sehap_contexts.
144    :param args:
145    :param contexts_file: path of contexts file
146    :param domain: true for domain, false for type
147    :return:
148    """
149    shutil.copyfile(contexts_file, contexts_file + "_bk")
150    err = 0
151    with open(contexts_file + "_bk", 'r') as contexts_read, open(contexts_file, 'w') as contexts_write:
152        pattern = re.compile(
153            r'apl=(system_core|system_basic|normal)\s+(name=\S+\s+)?domain=(\S+)\s+type=(\S+)\s*\n')
154        line_index = 0
155        for line in contexts_read:
156            line_ = line.lstrip()
157            line_index += 1
158            if line_.startswith('#') or line_.strip() == '':
159                contexts_write.write(line)
160                continue
161            match = pattern.match(line_)
162            if match:
163                if match.group(1) == 'normal' and match.group(2) != None:
164                    print(contexts_file + ":" +
165                          str(line_index) + " name cannot be set while apl=normal")
166                    err = 1
167                if domain:
168                    line = match.group(1) + " u:r:" + match.group(3) + ":s0\n"
169                else:
170                    line = match.group(1) + " u:object_r:" + \
171                        match.group(4) + ":s0\n"
172                contexts_write.write(line)
173            else:
174                print(contexts_file + ":" +
175                      str(line_index) + " format check fail")
176                err = 1
177        contexts_read.close()
178        contexts_write.close()
179    if err:
180        shutil.move(contexts_file + "_bk", contexts_file)
181        print("***********************************************************")
182        print("please check whether the format meets the following rules:")
183        print("[required format]: apl=* name=* domain=* type=*")
184        print("apl=*, apl should be one of system_core|system_basic|normal")
185        print("name=*, name is 'optional'")
186        print("domain=*, hapdomain selinux type")
187        print("type=*, hapdatafile selinux type")
188        print("***********************************************************")
189        raise Exception(err)
190    check_cmd = [os.path.join(args.tool_path, "sefcontext_compile"),
191                 "-o", contexts_file + ".bin",
192                 "-p", args.policy_file,
193                 contexts_file]
194    ret = subprocess.run(" ".join(check_cmd), shell=True).returncode
195    if ret != 0:
196        shutil.move(contexts_file + "_bk", contexts_file)
197        raise Exception(ret)
198    shutil.move(contexts_file + "_bk", contexts_file)
199    if os.path.exists(contexts_file + ".bin"):
200        os.unlink(contexts_file + ".bin")
201
202
203def build_file_contexts(args, output_path, policy_path):
204    file_contexts_list = traverse_folder_in_type(
205        policy_path, "file_contexts")
206
207    combined_file_contexts = os.path.join(output_path, "file_contexts")
208    combine_contexts_file(file_contexts_list, combined_file_contexts)
209
210    build_tmp_cmd = ["m4",
211                     "--fatal-warnings",
212                     "-s", combined_file_contexts, ">", os.path.join(output_path, "file_contexts.tmp")]
213    run_command(build_tmp_cmd)
214
215    check_redefinition(combined_file_contexts)
216
217    build_bin_cmd = [os.path.join(args.tool_path, "sefcontext_compile"),
218                     "-o", os.path.join(args.dst_dir, "file_contexts.bin"),
219                     "-p", args.policy_file,
220                     os.path.join(output_path, "file_contexts.tmp")]
221    run_command(build_bin_cmd)
222
223
224def build_common_contexts(args, output_path, contexts_file_name, policy_path):
225
226    contexts_list = traverse_folder_in_type(
227        policy_path, contexts_file_name)
228
229    combined_contexts = output_path + contexts_file_name
230    combine_contexts_file(contexts_list, combined_contexts)
231
232    check_common_contexts(args, combined_contexts)
233
234
235def build_sehap_contexts(args, output_path, policy_path):
236
237    contexts_list = traverse_folder_in_type(
238        policy_path, "sehap_contexts")
239
240    combined_contexts = os.path.join(output_path, "sehap_contexts")
241    combine_contexts_file(contexts_list, combined_contexts)
242
243    check_sehap_contexts(args, combined_contexts, 1)
244    check_sehap_contexts(args, combined_contexts, 0)
245
246
247def prepare_build_path(dir_list, root_dir, build_dir_list):
248
249    build_contexts_list = ["base/security/selinux/sepolicy/base", "base/security/selinux/sepolicy/ohos_policy"]
250    build_contexts_list += dir_list.split(":")
251
252    for i in build_contexts_list:
253        if i == "" or i == "default":
254            continue
255        path = os.path.join(root_dir, i)
256        if (os.path.exists(path)):
257            build_dir_list.append(path)
258        else:
259            print("following path not exists!! {}".format(path))
260            exit(-1)
261
262
263def main(args):
264
265    output_path = args.dst_dir
266
267    policy_path = []
268    prepare_build_path(args.policy_dir_list, args.source_root_dir, policy_path)
269
270    build_file_contexts(args, output_path, policy_path)
271    build_common_contexts(args, output_path, "service_contexts", policy_path)
272    build_common_contexts(args, output_path, "hdf_service_contexts", policy_path)
273    build_common_contexts(args, output_path, "parameter_contexts", policy_path)
274    build_sehap_contexts(args, output_path, policy_path)
275
276
277if __name__ == "__main__":
278    input_args = parse_args()
279    main(input_args)
280