From 193551db5ea0a1c0815875a233fbc9e2a729760c Mon Sep 17 00:00:00 2001 From: steven_q Date: Mon, 5 Jun 2023 19:02:50 +0800 Subject: [PATCH] policy map Signed-off-by: steven_q Change-Id: I3d10cdc1ab9a46b43247ff91972fa4a4721592ea --- .gitignore | 4 + BUILD.gn | 43 ++ .../policycoreutils/src/load_policy.cpp | 68 ++- scripts/build_policy.py | 235 +-------- scripts/build_policy_api.py | 489 ++++++++++++++++++ selinux.gni | 1 + 6 files changed, 608 insertions(+), 232 deletions(-) create mode 100644 scripts/build_policy_api.py diff --git a/.gitignore b/.gitignore index 6fd3b5233..78da5db4c 100644 --- a/.gitignore +++ b/.gitignore @@ -37,3 +37,7 @@ # Dirs sepolicy/hx* + +# py +__pycache__/ +*.pyc diff --git a/BUILD.gn b/BUILD.gn index cb1089bcb..083c64562 100644 --- a/BUILD.gn +++ b/BUILD.gn @@ -369,6 +369,13 @@ action("build_policy") { components, ] + if (components != "default") { + args += [ + "--vendor-policy-version", + "$vendor_policy_version", + ] + } + if (extra_args != "default") { foreach(arg, string_split(extra_args, " ")) { args += [ arg ] @@ -385,6 +392,9 @@ action("build_policy") { target_out_dir + "/prebuild_sepolicy.system.cil.sha256", target_out_dir + "/system.cil", target_out_dir + "/system.cil.sha256", + target_out_dir + "/$vendor_policy_version.cil", + target_out_dir + "/version", + target_out_dir + "/public.cil", ] } @@ -528,6 +538,16 @@ ohos_prebuilt_etc("build_updater_sepolicy") { install_images = [ "updater" ] } +ohos_prebuilt_etc("selinux_version") { + deps = [ ":build_policy" ] + source = target_out_dir + "/version" + license_file = "LICENSE" + part_name = "selinux" + subsystem_name = "security" + relative_install_dir = "selinux/" + install_images = [ "vendor" ] +} + ohos_prebuilt_etc("config") { deps = [ ":selinux_config" ] source = target_out_dir + "/config" @@ -615,6 +635,26 @@ ohos_prebuilt_etc("vendor_cil") { install_images = [ "vendor" ] } +ohos_prebuilt_etc("public_cil") { + deps = [ ":build_policy" ] + source = target_out_dir + "/public.cil" + license_file = "LICENSE" + part_name = "selinux" + subsystem_name = "security" + relative_install_dir = "selinux/" + install_images = [ "vendor" ] +} + +ohos_prebuilt_etc("version_cil") { + deps = [ ":build_policy" ] + source = target_out_dir + "/$vendor_policy_version.cil" + license_file = "LICENSE" + part_name = "selinux" + subsystem_name = "security" + relative_install_dir = "selinux/compatible/" + install_images = [ "system" ] +} + ohos_prebuilt_etc("prebuild_sepolicy_system_cil_sha256") { deps = [ ":build_policy" ] source = target_out_dir + "/prebuild_sepolicy.system.cil.sha256" @@ -678,11 +718,14 @@ group("selinux_group") { deps += [ ":system_cil", ":system_cil_sha256", + ":version_cil", ] } else if (components == "vendor") { deps += [ ":build_sepolicy", ":prebuild_sepolicy_system_cil_sha256", + ":public_cil", + ":selinux_version", ":vendor_cil", ] } else { diff --git a/interfaces/policycoreutils/src/load_policy.cpp b/interfaces/policycoreutils/src/load_policy.cpp index 86cbf35b3..b9e80b5b1 100644 --- a/interfaces/policycoreutils/src/load_policy.cpp +++ b/interfaces/policycoreutils/src/load_policy.cpp @@ -32,11 +32,14 @@ constexpr int32_t PIPE_NUM = 2; constexpr int32_t BUFF_SIZE = 1024; constexpr const char SYSTEM_CIL[] = "/system/etc/selinux/system.cil"; constexpr const char VENDOR_CIL[] = "/vendor/etc/selinux/vendor.cil"; +constexpr const char PUBLIC_CIL[] = "/vendor/etc/selinux/public.cil"; constexpr const char SYSTEM_CIL_HASH[] = "/system/etc/selinux/system.cil.sha256"; constexpr const char PRECOMPILED_POLICY_SYSTEM_CIL_HASH[] = "/vendor/etc/selinux/prebuild_sepolicy.system.cil.sha256"; constexpr const char COMPILE_OUTPUT_POLICY[] = "/dev/policy.31"; constexpr const char DEFAULT_POLICY[] = "/system/etc/selinux/targeted/policy/policy.31"; constexpr const char PRECOMPILED_POLICY[] = "/vendor/etc/selinux/prebuild_sepolicy/policy.31"; +constexpr const char VERSION_POLICY_PATH[] = "/vendor/etc/selinux/version"; +constexpr const char COMPATIBLE_CIL_PATH[] = "/system/etc/selinux/compatible/"; } // namespace static void InitSelinuxLog(void) @@ -82,6 +85,14 @@ static void DeleteTmpPolicyFile(const std::string &policyFile) } } +static bool GetVendorPolicyVersion(std::string & version) +{ + if (!ReadFileFirstLine(VERSION_POLICY_PATH, version)) { + return false; + } + return !version.empty(); +} + static bool ReadPolicyFile(const std::string &policyFile, void **data, size_t &size) { int fd = open(policyFile.c_str(), O_RDONLY | O_CLOEXEC); @@ -188,6 +199,32 @@ static bool LoadPolicy(void *data, size_t size) return true; } +static bool GetVersionPolicy(std::string &versionPolicy) +{ + std::string version; + if (!GetVendorPolicyVersion(version)) { + selinux_log(SELINUX_ERROR, "Get vendor policy version failed\n"); + return false; + } + std::string path(COMPATIBLE_CIL_PATH + version + ".cil"); + if (access(path.c_str(), F_OK) == 0) { + versionPolicy = path; + return true; + } + selinux_log(SELINUX_ERROR, "Get vendor version policy failed\n"); + return false; +} + +static bool GetPublicPolicy(std::string &publicPolicy) +{ + if (access(PUBLIC_CIL, F_OK) == 0) { + publicPolicy = PUBLIC_CIL; + return true; + } + selinux_log(SELINUX_ERROR, "Get vendor public policy failed\n"); + return false; +} + static std::vector CombineCompileCmd(void) { std::vector compileCmd = { @@ -206,6 +243,16 @@ static std::vector CombineCompileCmd(void) COMPILE_OUTPUT_POLICY, }; compileCmd.emplace_back(SYSTEM_CIL); + std::string versionPolicy; + if (GetVersionPolicy(versionPolicy)) { + selinux_log(SELINUX_WARNING, "Add policy %s\n", versionPolicy.c_str()); + compileCmd.emplace_back(versionPolicy.c_str()); + } + std::string publicPolicy; + if (GetPublicPolicy(publicPolicy)) { + selinux_log(SELINUX_WARNING, "Add policy %s\n", publicPolicy.c_str()); + compileCmd.emplace_back(publicPolicy.c_str()); + } compileCmd.emplace_back(nullptr); return compileCmd; } @@ -265,10 +312,25 @@ static bool CompilePolicy(void) return false; } (void)close(pipeFd[1]); - char buf[BUFF_SIZE] = {0}; - while (read(pipeFd[0], buf, BUFF_SIZE - 1) > 0) { - selinux_log(SELINUX_ERROR, "Selinux compile result: %s\n", buf); + + FILE *fp = fdopen(pipeFd[0], "r"); + if (fp != nullptr) { + char buf[BUFF_SIZE] = {0}; + while (fgets(buf, sizeof(buf) - 1, fp) != nullptr) { + size_t n = strlen(buf); + if (n == 0) { + continue; + } + if (buf[n - 1] == '\n') { + buf[n - 1] = '\0'; + } + if (strstr(buf, "Failed") != nullptr) { + selinux_log(SELINUX_ERROR, "SELinux compile result: %s\n", buf); + } + } + fclose(fp); } + (void)close(pipeFd[0]); return WaitForChild(pid); diff --git a/scripts/build_policy.py b/scripts/build_policy.py index 0f6919b73..5a97c5a67 100755 --- a/scripts/build_policy.py +++ b/scripts/build_policy.py @@ -2,7 +2,7 @@ # coding: utf-8 """ -Copyright (c) 2021-2022 Huawei Device Co., Ltd. +Copyright (c) 2021-2023 Huawei Device Co., Ltd. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at @@ -19,27 +19,11 @@ limitations under the License. import os import argparse +import re import subprocess import tempfile import shutil - -# list of all macros and te for sepolicy build -SEPOLICY_TYPE_LIST = ["security_classes", - "initial_sids", - "access_vectors", - "glb_perm_def.spt", - "glb_never_def.spt", - "mls", - "policy_cap", - "glb_te_def.spt", - "attributes", - ".te", - "glb_roles.spt", - "users", - "initial_sid_contexts", - "fs_use", - "virtfs_contexts", - ] +import build_policy_api def parse_args(): @@ -58,218 +42,11 @@ def parse_args(): help='build for updater target', required=True) parser.add_argument('--components', help='system or vendor or default', required=True) + parser.add_argument('--vendor-policy-version', + help='plat version of vendor policy', required=False) return parser.parse_args() -def traverse_folder_in_dir_name(search_dir, folder_suffix): - folder_list = [] - for root, dirs, _ in os.walk(search_dir): - for dir_i in dirs: - if dir_i == folder_suffix: - folder_list.append(os.path.join(root, dir_i)) - return folder_list - - -def traverse_folder_in_type(search_dir, file_suffix, build_root): - policy_file_list = [] - flag = 0 - for root, _, files in os.walk(search_dir): - for each_file in files: - if each_file.endswith(file_suffix): - path = os.path.join(root, each_file) - rel_path = os.path.relpath(path, build_root) - flag |= check_empty_row(rel_path) - policy_file_list.append(rel_path) - policy_file_list.sort() - return " ".join(str(x) for x in policy_file_list), flag - - -def traverse_file_in_each_type(folder_list, sepolicy_type_list, build_root): - policy_files = "" - err = 0 - for policy_type in sepolicy_type_list: - for folder in folder_list: - str_tra, flag = traverse_folder_in_type(folder, policy_type, build_root) - err |= flag - str_seq = (policy_files, str_tra) - policy_files = " ".join(str_seq) - if err: - raise Exception(err) - return policy_files - - -def check_empty_row(policy_file_list): - """ - Check whether the last line of te is empty. - :param policy_file_list: list of te file - :return: - """ - err = 0 - with open(policy_file_list, 'r') as fp: - lines = fp.readlines() - if len(lines) != 0: - last_line = lines[-1] - if '\n' not in last_line: - print(policy_file_list + " :" + " need an empty line at end \n") - err = 1 - return err - - -def run_command(in_cmd): - - cmdstr = " ".join(in_cmd) - ret = subprocess.run(cmdstr, shell=True).returncode - if ret != 0: - raise Exception(ret) - - -def build_conf(args, output_conf, input_policy_file_list): - m4_args = "-D build_with_debug=" + args.debug_version + " " - m4_args += "-D build_with_updater=" + args.updater_version + " " - - build_conf_cmd = ["m4", - "--fatal-warnings", m4_args, - "-s", input_policy_file_list, ">", output_conf] - - run_command(build_conf_cmd) - - -def build_cil(args, output_cil, input_conf): - check_policy_cmd = [os.path.join(args.tool_path, "checkpolicy"), - input_conf, - "-M -C -c 31", - "-o " + output_cil] - run_command(check_policy_cmd) - - -def build_policy(args, output_policy, vendor_cil, system_cil): - build_policy_cmd = [os.path.join(args.tool_path, "secilc"), - vendor_cil, - system_cil, - "-m -M true -G -c 31", - "-f /dev/null", - "-o " + output_policy] - run_command(build_policy_cmd) - - - -def prepare_build_path(dir_list, root_dir, build_dir_list, sepolicy_path): - build_policy_list = [os.path.join(sepolicy_path, "base"), os.path.join(sepolicy_path, "ohos_policy")] - build_policy_list += dir_list.split(":") - - for i in build_policy_list: - if i == "" or i == "default": - continue - path = os.path.join(root_dir, i) - if (os.path.exists(path)): - build_dir_list.append(path) - else: - print("following path not exists!! {}".format(path)) - exit(-1) - - -def filter_out(pattern_file, input_file): - patterns = [] - with open(pattern_file, 'r') as pat_file: - patterns.extend(pat_file.readlines()) - - tmp_output = tempfile.NamedTemporaryFile() - with open(input_file, 'r') as in_file: - tmp_output.writelines(line.encode(encoding='utf-8') for line in in_file.readlines() - if line not in patterns) - tmp_output.write("\n".encode(encoding='utf-8')) - tmp_output.flush() - shutil.copyfile(tmp_output.name, input_file) - - -def generate_hash_file(input_file, output_file): - build_policy_cmd = ["sha256sum", - input_file, - "| cut -d' ' -f1", - ">", - output_file] - run_command(build_policy_cmd) - - -def compile_sepolicy(args): - output_path = os.path.abspath(os.path.dirname(args.dst_file)) - build_root = os.path.abspath(os.path.join(args.tool_path, "../../..")) - sepolicy_path = os.path.join(args.source_root_dir, "base/security/selinux/sepolicy/") - dir_list = [] - prepare_build_path(args.policy_dir_list, args.source_root_dir, dir_list, sepolicy_path) - min_policy = [os.path.join(sepolicy_path, "min")] - system_policy = [] - public_policy = [] - vendor_policy = [] - - for item in dir_list: - public_policy += traverse_folder_in_dir_name(item, "public") - system_policy += traverse_folder_in_dir_name(item, "system") - vendor_policy += traverse_folder_in_dir_name(item, "vendor") - - # list of all policy folders - system_folder_list = public_policy + system_policy - vendor_folder_list = public_policy + vendor_policy + min_policy - - # add temp dirs base/te folders - system_folder_list.append(os.path.join(sepolicy_path, "base/te")) - vendor_folder_list.append(os.path.join(sepolicy_path, "base/te")) - - # list of all policy files - system_policy_file_list = traverse_file_in_each_type(system_folder_list, SEPOLICY_TYPE_LIST, build_root) - vendor_policy_file_list = traverse_file_in_each_type(vendor_folder_list, SEPOLICY_TYPE_LIST, build_root) - min_policy_file_list = traverse_file_in_each_type(min_policy, SEPOLICY_TYPE_LIST, build_root) - - system_output_conf = os.path.join(output_path, "system.conf") - vendor_output_conf = os.path.join(output_path, "vendor.conf") - min_output_conf = os.path.join(output_path, "min.conf") - - system_cil_path = os.path.join(output_path, "system.cil") - vendor_cil_path = os.path.join(output_path, "vendor.cil") - min_cil_path = os.path.join(output_path, "min.cil") - - # build system.conf - build_conf(args, system_output_conf, system_policy_file_list) - # build system.cil - build_cil(args, system_cil_path, system_output_conf) - - if args.components == "system": - system_cil_sha256 = os.path.join(output_path, "system.cil.sha256") - generate_hash_file(system_cil_path, system_cil_sha256) - - elif args.components == "vendor": - prebuild_sepolicy_system_cil_sha256 = os.path.join(output_path, "prebuild_sepolicy.system.cil.sha256") - generate_hash_file(system_cil_path, prebuild_sepolicy_system_cil_sha256) - - # build vendor.conf - build_conf(args, vendor_output_conf, vendor_policy_file_list) - # build vendor.cil - build_cil(args, vendor_cil_path, vendor_output_conf) - - # build min.conf - build_conf(args, min_output_conf, min_policy_file_list) - # build min.cil - build_cil(args, min_cil_path, min_output_conf) - - filter_out(min_cil_path, vendor_cil_path) - build_policy(args, args.dst_file, vendor_cil_path, system_cil_path) - - -def main(args): - # check both debug and release sepolicy - origin_debug_version = args.debug_version - if args.debug_version == "true": - args.debug_version = "false" - compile_sepolicy(args) - else: - args.debug_version = "true" - compile_sepolicy(args) - - # build target policy according to desire debug_version - args.debug_version = origin_debug_version - compile_sepolicy(args) - - if __name__ == "__main__": input_args = parse_args() - main(input_args) + build_policy_api.main(input_args) diff --git a/scripts/build_policy_api.py b/scripts/build_policy_api.py new file mode 100644 index 000000000..bfd7accc2 --- /dev/null +++ b/scripts/build_policy_api.py @@ -0,0 +1,489 @@ +#!/usr/bin/env python +# coding: utf-8 + +""" +Copyright (c) 2023 Huawei Device Co., Ltd. +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +""" + +import os +import re +import shutil +import subprocess +import tempfile + +SYSTEM_CIL_HASH = "system.cil.sha256" +PREBUILD_SEPOLICY_SYSTEM_CIL_HASH = "prebuild_sepolicy.system.cil.sha256" + +# list of all macros and te for sepolicy build +SEPOLICY_TYPE_LIST = ["security_classes", + "initial_sids", + "access_vectors", + "glb_perm_def.spt", + "glb_never_def.spt", + "mls", + "policy_cap", + "glb_te_def.spt", + "attributes", + ".te", + "glb_roles.spt", + "users", + "initial_sid_contexts", + "fs_use", + "virtfs_contexts", + ] + +POLICY_TYPE_LIST = ["allow", "auditallow", "dontaudit", + "allowx", "auditallowx", "dontauditx", + "neverallow", "neverallowx", ] + + +class PolicyDirList(object): + def __init__(self, min_policy_dir_list, system_policy_dir_list, vendor_policy_dir_list, public_policy_dir_list): + self.min_policy_dir_list = min_policy_dir_list + self.system_policy_dir_list = system_policy_dir_list + self.vendor_policy_dir_list = vendor_policy_dir_list + self.public_policy_dir_list = public_policy_dir_list + + +class PolicyFileList(object): + def __init__(self, min_policy_file_list, system_policy_file_list, vendor_policy_file_list, public_policy_file_list): + self.min_policy_file_list = min_policy_file_list + self.system_policy_file_list = system_policy_file_list + self.vendor_policy_file_list = vendor_policy_file_list + self.public_policy_file_list = public_policy_file_list + + +def traverse_folder_in_dir_name(search_dir, folder_suffix): + folder_list = [] + for root, dirs, _ in os.walk(search_dir): + for dir_i in dirs: + if dir_i == folder_suffix: + folder_list.append(os.path.join(root, dir_i)) + return folder_list + + +def traverse_folder_in_type(search_dir, file_suffix, build_root): + policy_file_list = [] + flag = 0 + for root, _, files in os.walk(search_dir): + for each_file in files: + if each_file.endswith(file_suffix): + path = os.path.join(root, each_file) + rel_path = os.path.relpath(path, build_root) + flag |= check_empty_row(rel_path) + policy_file_list.append(rel_path) + policy_file_list.sort() + return policy_file_list, flag + + +def traverse_file_in_each_type(folder_list, sepolicy_type_list, build_root): + policy_files_list = [] + err = 0 + for policy_type in sepolicy_type_list: + for folder in folder_list: + type_file_list, flag = traverse_folder_in_type( + folder, policy_type, build_root) + err |= flag + policy_files_list.extend(type_file_list) + if err: + raise Exception(err) + return policy_files_list + + +def check_empty_row(policy_file): + """ + Check whether the last line of te file is empty. + :param policy_file: te file + :return: + """ + err = 0 + with open(policy_file, 'r') as fp: + lines = fp.readlines() + if len(lines) == 0: + return 0 + last_line = lines[-1] + if '\n' not in last_line: + print("".join([policy_file, " : need an empty line at end\n"])) + err = 1 + return err + + +def run_command(in_cmd): + cmdstr = " ".join(in_cmd) + ret = subprocess.run(cmdstr, shell=True).returncode + if ret != 0: + raise Exception(ret) + + +def build_conf(args, output_conf, file_list): + m4_args = ["-D", "build_with_debug=" + args.debug_version] + m4_args += ["-D", "build_with_updater=" + args.updater_version] + build_conf_cmd = ["m4", "-s", "--fatal-warnings"] + m4_args + file_list + with open(output_conf, 'w') as fd: + ret = subprocess.run(build_conf_cmd, shell=False, stdout=fd).returncode + if ret != 0: + raise Exception(ret) + + +def build_cil(args, output_cil, input_conf): + check_policy_cmd = [os.path.join(args.tool_path, "checkpolicy"), + input_conf, + "-M -C -c 31", + "-o " + output_cil] + run_command(check_policy_cmd) + + +def add_version(version, string): + return "".join([string, "_", version]) + + +def simplify_string(string): + return string.replace('(', '').replace(')', '').replace('\n', '') + + +def deal_with_roletype(version, cil_write, elem_list, type_set, file, line): + if len(elem_list) < 3: + print('Error: invalid roletype in %s:%d' % (file, line)) + raise Exception(1) + + sub_string = simplify_string(elem_list[2]) + if sub_string in type_set: + cil_write.write('(typeattribute ' + add_version(version, sub_string) + ')\n') + elem_list[2] = elem_list[2].replace( + sub_string, add_version(version, sub_string)) + cil_write.write(" ".join(elem_list)) + + +def deal_with_typeattribute(version, cil_write, elem_list, type_set, file, line): + if len(elem_list) < 2: + print('Error: invalid typeattribute in %s:%d' % (file, line)) + raise Exception(1) + + sub_string = simplify_string(elem_list[1]) + if sub_string.startswith("base_typeattr_"): + elem_list[1] = elem_list[1].replace( + sub_string, add_version(version, sub_string)) + cil_write.write(" ".join(elem_list)) + + +def deal_with_typeattributeset(version, cil_write, elem_list, type_set, file, line): + if len(elem_list) < 2: + print('Error: invalid typeattributeset in %s:%d' % (file, line)) + raise Exception(1) + + for index, elem in enumerate(elem_list[1:]): + sub_string = simplify_string(elem) + if sub_string.startswith("base_typeattr_") or sub_string in type_set: + elem_list[index + 1] = elem.replace(sub_string, add_version(version, sub_string)) + cil_write.write(" ".join(elem_list)) + + +def deal_with_policy(version, cil_write, elem_list, type_set, file, line): + if len(elem_list) < 4: + print('Error: invalid policy in %s:%d' % (file, line)) + raise Exception(1) + + for index, elem in enumerate(elem_list[1:3]): + sub_string = simplify_string(elem) + if sub_string.startswith("base_typeattr_") or sub_string in type_set: + elem_list[index + 1] = elem.replace(sub_string, add_version(version, sub_string)) + cil_write.write(" ".join(elem_list)) + + +def deal_with_type(version, cil_write, elem_list, file, line): + if len(elem_list) < 2: + print('Error: invalid type in %s:%d' % (file, line)) + raise Exception(1) + + sub_string = simplify_string(elem_list[1]) + cil_write.write(" ".join(['(typeattributeset', add_version(version, sub_string), '(', sub_string, '))\n'])) + cil_write.write(" ".join(['(expandtypeattribute', '(', add_version(version, sub_string), ') true)\n'])) + cil_write.write(" ".join(['(typeattribute', add_version(version, sub_string), ')\n'])) + + +def build_version_cil(version, cil_file_input, cil_file_output, type_set): + index = 0 + with open(cil_file_input, 'r') as cil_read, open(cil_file_output, 'w') as cil_write: + for line in cil_read: + index += 1 + if not line.startswith('('): + continue + + elem_list = line.split(' ') + if not elem_list: + continue + + if elem_list[0] == '(type': + cil_write.write(line) + elif elem_list[0] == '(roletype': + deal_with_roletype(version, cil_write, elem_list, type_set, cil_file_input, line) + elif elem_list[0] == '(typeattribute': + deal_with_typeattribute(version, cil_write, elem_list, type_set, cil_file_input, line) + elif elem_list[0] == '(typeattributeset': + deal_with_typeattributeset(version, cil_write, elem_list, type_set, cil_file_input, line) + elif simplify_string(elem_list[0]) in POLICY_TYPE_LIST: + deal_with_policy(version, cil_write, elem_list, type_set, cil_file_input, line) + else: + cil_write.write(line) + + +def build_type_version_cil(version, cil_file_input, cil_file_output): + index = 0 + with open(cil_file_input, 'r') as cil_read, open(cil_file_output, 'w') as cil_write: + for line in cil_read: + index += 1 + if not line.startswith('('): + continue + + elem_list = line.split(' ') + if not elem_list: + continue + + if elem_list[0] == '(type': + deal_with_type(version, cil_write, elem_list, line, index) + + +def get_type_set(cil_file_input): + pattern_type = re.compile(r'^\(type (.*)\)$') + pattern_typeattribute = re.compile(r'^\(type_attribute (base_typeattr_[0-9]+)\)$') + type_set = set() + with open(cil_file_input, 'r') as cil_read: + for line in cil_read: + match_type = pattern_type.match(line) + match_typeattribute = pattern_typeattribute.match(line) + if match_type: + type_set.add(match_type.group(1)) + elif match_typeattribute: + type_set.add(match_typeattribute.group(1)) + return type_set + + +def build_binary_policy(tool_path, output_policy, check_neverallow, cil_list): + build_policy_cmd = [os.path.join(tool_path, "secilc"), + " ".join(cil_list), + "-m -M true -G -c 31", + "-f /dev/null", + "-o " + output_policy] + if not check_neverallow: + build_policy_cmd.append("-N") + run_command(build_policy_cmd) + + +def prepare_build_path(dir_list, root_dir, build_dir_list, sepolicy_path): + build_policy_list = [os.path.join(sepolicy_path, "base"), os.path.join(sepolicy_path, "ohos_policy")] + build_policy_list += dir_list.split(":") + + for i in build_policy_list: + if i == "" or i == "default": + continue + path = os.path.join(root_dir, i) + if (os.path.exists(path)): + build_dir_list.append(path) + else: + print("following path not exists!! {}".format(path)) + exit(-1) + + +def get_policy_dir_list(args): + sepolicy_path = os.path.join(args.source_root_dir, "base/security/selinux/sepolicy/") + dir_list = [] + prepare_build_path(args.policy_dir_list, args.source_root_dir, dir_list, sepolicy_path) + min_policy_dir_list = [os.path.join(sepolicy_path, "min")] + system_policy = [] + public_policy = [] + vendor_policy = [] + + for item in dir_list: + public_policy += traverse_folder_in_dir_name(item, "public") + system_policy += traverse_folder_in_dir_name(item, "system") + vendor_policy += traverse_folder_in_dir_name(item, "vendor") + + # list of all policy folders + system_policy_dir_list = public_policy + system_policy + vendor_policy_dir_list = public_policy + vendor_policy + min_policy_dir_list + public_policy_dir_list = public_policy + min_policy_dir_list + + # add temp dirs base/te folders + system_policy_dir_list.append(os.path.join(sepolicy_path, "base/te")) + vendor_policy_dir_list.append(os.path.join(sepolicy_path, "base/te")) + public_policy_dir_list.append(os.path.join(sepolicy_path, "base/te")) + + return PolicyDirList(min_policy_dir_list, system_policy_dir_list, vendor_policy_dir_list, public_policy_dir_list) + + +def get_policy_file_list(args, dir_list_object): + build_root = os.path.abspath(os.path.join(args.tool_path, "../../..")) + # list of all policy files + system_policy_file_list = traverse_file_in_each_type( + dir_list_object.system_policy_dir_list, SEPOLICY_TYPE_LIST, build_root) + vendor_policy_file_list = traverse_file_in_each_type( + dir_list_object.vendor_policy_dir_list, SEPOLICY_TYPE_LIST, build_root) + public_policy_file_list = traverse_file_in_each_type( + dir_list_object.public_policy_dir_list, SEPOLICY_TYPE_LIST, build_root) + min_policy_file_list = traverse_file_in_each_type( + dir_list_object.min_policy_dir_list, SEPOLICY_TYPE_LIST, build_root) + + return PolicyFileList(min_policy_file_list, system_policy_file_list, vendor_policy_file_list, + public_policy_file_list) + + +def filter_out(pattern_file, input_file): + patterns = [] + with open(pattern_file, 'r') as pat_file: + patterns.extend(pat_file.readlines()) + + tmp_output = tempfile.NamedTemporaryFile() + with open(input_file, 'r') as in_file: + tmp_output.writelines(line.encode(encoding='utf-8') for line in in_file.readlines() + if line not in patterns) + tmp_output.write("\n".encode(encoding='utf-8')) + tmp_output.flush() + shutil.copyfile(tmp_output.name, input_file) + + +def generate_hash_file(input_file_list, output_file): + build_policy_cmd = ["cat", + " ".join(input_file_list), + "| sha256sum", + "| cut -d' ' -f1", + ">", + output_file] + run_command(build_policy_cmd) + + +def generate_version_file(args, output_file): + cmd = ["echo", args.vendor_policy_version, + ">", output_file] + run_command(cmd) + + +def generate_default_policy(args, system_policy_file_list, vendor_policy_file_list, min_policy_file_list): + output_path = os.path.abspath(os.path.dirname(args.dst_file)) + system_output_conf = os.path.join(output_path, "system.conf") + vendor_output_conf = os.path.join(output_path, "vendor.conf") + min_output_conf = os.path.join(output_path, "min.conf") + + system_cil_path = os.path.join(output_path, "system.cil") + vendor_cil_path = os.path.join(output_path, "vendor.cil") + min_cil_path = os.path.join(output_path, "min.cil") + + # build system.conf + build_conf(args, system_output_conf, system_policy_file_list) + # build system.cil + build_cil(args, system_cil_path, system_output_conf) + + # build vendor.conf + build_conf(args, vendor_output_conf, vendor_policy_file_list) + # build vendor.cil + build_cil(args, vendor_cil_path, vendor_output_conf) + + # build min.conf + build_conf(args, min_output_conf, min_policy_file_list) + # build min.cil + build_cil(args, min_cil_path, min_output_conf) + + filter_out(min_cil_path, vendor_cil_path) + + return [vendor_cil_path, system_cil_path] + + +def generate_special_policy(args, system_policy_file_list, vendor_policy_file_list, public_policy_file_list, + min_policy_file_list): + output_path = os.path.abspath(os.path.dirname(args.dst_file)) + system_output_conf = os.path.join(output_path, "system.conf") + vendor_output_conf = os.path.join(output_path, "vendor.conf") + public_output_conf = os.path.join(output_path, "public.conf") + min_output_conf = os.path.join(output_path, "min.conf") + + vendor_origin_cil_path = os.path.join(output_path, "vendor_origin.cil") + public_origin_cil_path = os.path.join(output_path, "public_origin.cil") + min_cil_path = os.path.join(output_path, "min.cil") + + # output file + system_cil_path = os.path.join(output_path, "system.cil") + vendor_cil_path = os.path.join(output_path, "vendor.cil") + public_version_cil_path = os.path.join(output_path, "public.cil") + type_version_cil_path = os.path.join(output_path, "".join([args.vendor_policy_version, ".cil"])) + + # build system.conf + build_conf(args, system_output_conf, system_policy_file_list) + # build system.cil + build_cil(args, system_cil_path, system_output_conf) + + # build min.cil + build_conf(args, min_output_conf, min_policy_file_list) + build_cil(args, min_cil_path, min_output_conf) + + # build public.cil + build_conf(args, public_output_conf, public_policy_file_list) + build_cil(args, public_origin_cil_path, public_output_conf) + type_set = get_type_set(public_origin_cil_path) + filter_out(min_cil_path, public_origin_cil_path) + build_version_cil(args.vendor_policy_version, public_origin_cil_path, public_version_cil_path, type_set) + + # build vendor.cil + build_conf(args, vendor_output_conf, vendor_policy_file_list) + build_cil(args, vendor_origin_cil_path, vendor_output_conf) + filter_out(min_cil_path, vendor_origin_cil_path) + build_version_cil(args.vendor_policy_version, vendor_origin_cil_path, vendor_cil_path, type_set) + filter_out(public_version_cil_path, vendor_cil_path) + + build_type_version_cil(args.vendor_policy_version, public_origin_cil_path, type_version_cil_path) + + if args.components == "system": + generate_hash_file([system_cil_path, type_version_cil_path], + os.path.join(output_path, SYSTEM_CIL_HASH)) + + elif args.components == "vendor": + generate_hash_file([system_cil_path, type_version_cil_path], os.path.join( + output_path, PREBUILD_SEPOLICY_SYSTEM_CIL_HASH)) + + version_file = os.path.join(output_path, "version") + generate_version_file(args, version_file) + + return [vendor_cil_path, system_cil_path, type_version_cil_path, public_version_cil_path] + + +def compile_sepolicy(args): + dir_list_object = get_policy_dir_list(args) + file_list_object = get_policy_file_list(args, dir_list_object) + + cil_list = [] + if args.components == "default" or args.updater_version == "enable": + cil_list += generate_default_policy(args, file_list_object.system_policy_file_list, + file_list_object.vendor_policy_file_list, + file_list_object.min_policy_file_list) + else: + cil_list += generate_special_policy(args, file_list_object.system_policy_file_list, + file_list_object.vendor_policy_file_list, + file_list_object.public_policy_file_list, + file_list_object.min_policy_file_list) + + build_binary_policy(args.tool_path, args.dst_file, True, cil_list) + + +def main(args): + # check both debug and release sepolicy + origin_debug_version = args.debug_version + if args.debug_version == "true": + args.debug_version = "false" + compile_sepolicy(args) + else: + args.debug_version = "true" + compile_sepolicy(args) + + # build target policy according to desire debug_version + args.debug_version = origin_debug_version + compile_sepolicy(args) diff --git a/selinux.gni b/selinux.gni index 870e88439..dae868cde 100644 --- a/selinux.gni +++ b/selinux.gni @@ -17,6 +17,7 @@ THIRD_PARTY_DIR = "//third_party" declare_args() { selinux_build_path = "default" components = "default" + vendor_policy_version = "40" special_build_policy_script = "default" extra_args = "default" }