From cc4ff836d27aa375ccbbb3ae7cab9dc4ed9632bd Mon Sep 17 00:00:00 2001 From: lihehe Date: Fri, 9 May 2025 16:14:00 +0800 Subject: [PATCH] add device types and generate permissions from security_access_token Signed-off-by: lihehe Change-Id: Ie5e58cfb9bc4ffe0621252059741e87056a27fe1 --- frameworks/common/BUILD.gn | 22 +- frameworks/common/permission_check.py | 117 +++++++++ .../common/permission_definition_parser.py | 46 +++- .../accesstoken/test/unittest/BUILD.gn | 1 - .../check_permission_map_test.cpp | 227 ------------------ .../check_permission_map_test.h | 45 ---- .../permission_definitions.json | 17 +- 7 files changed, 185 insertions(+), 290 deletions(-) create mode 100755 frameworks/common/permission_check.py delete mode 100644 interfaces/innerkits/accesstoken/test/unittest/PermissionsTest/check_permission_map_test.cpp delete mode 100644 interfaces/innerkits/accesstoken/test/unittest/PermissionsTest/check_permission_map_test.h diff --git a/frameworks/common/BUILD.gn b/frameworks/common/BUILD.gn index a970dab5e..30c9f2b95 100644 --- a/frameworks/common/BUILD.gn +++ b/frameworks/common/BUILD.gn @@ -19,6 +19,20 @@ config("accesstoken_common_cxx_public_config") { include_dirs = [ "include" ] } +action("permission_definition_check") { + script = "permission_check.py" + args = [ + "--source-root-dir", + rebase_path("//", root_build_dir), + "--input-full-permissions", + rebase_path("${access_token_path}") + + "/services/accesstokenmanager/permission_definitions.json", + ] + inputs = [ rebase_path("${access_token_path}") + + "/services/accesstokenmanager/permission_definitions.json" ] + outputs = [ "$target_out_dir" ] +} + action("permission_definition_parse") { script = "permission_definition_parser.py" inputs = [ rebase_path("${access_token_path}") + @@ -29,8 +43,13 @@ action("permission_definition_parse") { "/services/accesstokenmanager/permission_definitions.json", "--output-path", rebase_path(target_out_dir) + "/permission_map_constant.h", + "--target-platform", + target_platform, ] - outputs = [ "$target_out_dir" ] + outputs = [ "$target_out_dir" + "/permission_map_constant.h" ] + if (!ohos_indep_compiler_enable) { + deps = [ ":permission_definition_check" ] + } } ohos_static_library("accesstoken_static_log") { @@ -96,6 +115,7 @@ ohos_shared_library("accesstoken_common_cxx") { ":accesstoken_static_log", ":permission_definition_parse", ] + external_deps = [ "c_utils:utils", "hilog:libhilog", diff --git a/frameworks/common/permission_check.py b/frameworks/common/permission_check.py new file mode 100755 index 000000000..4cbcce5fa --- /dev/null +++ b/frameworks/common/permission_check.py @@ -0,0 +1,117 @@ +#!/usr/bin/env python +# coding: utf-8 + +""" +Copyright (c) 2025 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 json +import argparse +import os + + +REQUIRED_ATTRS = [ + "name", + "grantMode", + "availableLevel", + "since", + "provisionEnable", + "distributedSceneEnable" +] + + +ATTRS_ONLY_IN_RESOURCE = [ + "label", + "description" +] + + +def parse_definition_json(path): + permission_maps = {} + with open(path, "r", encoding="utf-8") as f: + data = json.load(f) + for perm in data["definePermissions"]: + permission_maps[perm["name"]] = perm + return permission_maps + + +def parse_module_json(path): + permission_maps = {} + if not os.path.exists(path): + return {} + with open(path, "r", encoding="utf-8") as f: + data = json.load(f) + for perm in data["module"]["definePermissions"]: + permission_maps[perm["name"]] = perm + return permission_maps + + +def check_required_param(defs, filename): + for attr in REQUIRED_ATTRS: + if not attr in defs: + raise Exception("Not found {} of {} in {}".format( + attr, defs["name"], filename)) + + +def check_consistency(def_in_module, full_def): + for attr, value in full_def.items(): + if not attr in def_in_module: + continue + if not value == def_in_module[attr]: + raise Exception("{} of {} is inconsistent in module.json and permission_definition.json".format( + attr, def_in_module["name"])) + + for attr in def_in_module.keys(): + if attr in ATTRS_ONLY_IN_RESOURCE: + continue + elif not attr in full_def: + raise Exception("{} of {} should be define in permission_definition.json".format(attr, + def_in_module["name"])) + + +def check_maps(module_map, definition_map): + for name, perm_def in definition_map.items(): + if not "availableType" in perm_def: + raise Exception("Cannot define permission {} without availableType " \ + "in permission_definition.json".format(name)) + if perm_def["availableType"] == "SERVICE": + if name in module_map: + raise Exception("Cannot define permission {} for SERVICE in module.json".format(name)) + continue + if not name in module_map: + raise Exception("To add permission definition of {} in system_global_resource.".format(name)) + check_required_param(module_map[name], "module.json") + check_required_param(definition_map[name], "permission_definition.json") + check_consistency(module_map[name], definition_map[name]) + + +def parse_args(): + parser = argparse.ArgumentParser() + parser.add_argument('--source-root-dir', help='build root dir', required=True) + parser.add_argument('--input-full-permissions', help='json file for permission definition', required=True) + return parser.parse_args() + + +if __name__ == "__main__": + input_args = parse_args() + module_json_path = os.path.join("base/global/system_resources/systemres/main", "module.json") + module_json_path = os.path.join(input_args.source_root_dir, module_json_path) + module_json_map = parse_module_json(module_json_path) + if not module_json_map: + print("Not found {}, no need to check consistency.".format(module_json_path)) + exit(0) + full_permissions_map = parse_definition_json(input_args.input_full_permissions) + check_maps(module_json_map, full_permissions_map) + print("Check permission consistency pass!") \ No newline at end of file diff --git a/frameworks/common/permission_definition_parser.py b/frameworks/common/permission_definition_parser.py index 924f3734f..014e65fea 100755 --- a/frameworks/common/permission_definition_parser.py +++ b/frameworks/common/permission_definition_parser.py @@ -82,6 +82,15 @@ JSON_VALUE_CONVERT_TO_CPP_DICT = { "system_core": "APL_SYSTEM_CORE", } +CONVERT_TARGET_PLATFORM = { + "phone": "phone", + "watch": "wearable", + "tablet": "tablet", + "pc": "2in1", + "tv": "tv", + "car": "car", +} + class PermissionDef(object): def __init__(self, permission_def_dict, code): @@ -114,6 +123,17 @@ class PermissionDef(object): else: self.has_value = "false" + if permission_def_dict["since"] >= 20 and not "deviceTypes" in permission_def_dict: + raise Exception("No deviceTypes in permission difinition of {}".format(self.name)) + + if "deviceTypes" in permission_def_dict: + if isinstance(permission_def_dict["deviceTypes"], list) and len(permission_def_dict["deviceTypes"]) > 0: + self.device_types = permission_def_dict["deviceTypes"] + else: + raise Exception("Must be filled with available device type list, name = {}".format(self.name)) + else: + self.device_types = ["general"] + self.code = code def dump_permission_name(self): @@ -129,8 +149,15 @@ class PermissionDef(object): ) return entry + def check_device_type(self, target_platform): + if "general" in self.device_types: + return True + if target_platform in self.device_types: + return True + return False + -def parse_json(path): +def parse_json(path, platform): extend_perm = { 'name' : 'ohos.permission.KERNEL_ATM_SELF_USE', 'grantMode' : 'system_grant', @@ -149,12 +176,11 @@ def parse_json(path): with open(path, "r", encoding="utf-8") as f: data = json.load(f) index = 0 - for perm in data["systemGrantPermissions"]: - permission_list.append(PermissionDef(perm, index)) - index += 1 - - for perm in data["userGrantPermissions"]: - permission_list.append(PermissionDef(perm, index)) + for perm in data["definePermissions"]: + perm_def = PermissionDef(perm, index) + if not perm_def.check_device_type(platform): + continue + permission_list.append(perm_def) index += 1 permission_list.append(PermissionDef(extend_perm, index)) return permission_list @@ -177,10 +203,14 @@ def parse_args(): parser = argparse.ArgumentParser() parser.add_argument('--output-path', help='the output cpp path', required=True) parser.add_argument('--input-json', help='json file for permission difinition', required=True) + parser.add_argument('--target-platform', help='build target platform', required=True) return parser.parse_args() if __name__ == "__main__": input_args = parse_args() - permission_list = parse_json(input_args.input_json) + curr_platform = "general" + if input_args.target_platform in CONVERT_TARGET_PLATFORM: + curr_platform = CONVERT_TARGET_PLATFORM[input_args.target_platform] + permission_list = parse_json(input_args.input_json, curr_platform) convert_to_cpp(input_args.output_path, permission_list) \ No newline at end of file diff --git a/interfaces/innerkits/accesstoken/test/unittest/BUILD.gn b/interfaces/innerkits/accesstoken/test/unittest/BUILD.gn index c8267ecdb..54a0bce2c 100755 --- a/interfaces/innerkits/accesstoken/test/unittest/BUILD.gn +++ b/interfaces/innerkits/accesstoken/test/unittest/BUILD.gn @@ -62,7 +62,6 @@ ohos_unittest("libaccesstoken_sdk_test") { "PermisionDialogTest/get_self_permission_state_test.cpp", "PermisionDialogTest/request_permission_on_setting_test.cpp", "PermisionDialogTest/set_perm_dialog_cap_test.cpp", - "PermissionsTest/check_permission_map_test.cpp", "PermissionsTest/clear_user_granted__permission_state_test.cpp", "PermissionsTest/get_permission_test.cpp", "PermissionsTest/grant_permission_for_specified_time_test.cpp", diff --git a/interfaces/innerkits/accesstoken/test/unittest/PermissionsTest/check_permission_map_test.cpp b/interfaces/innerkits/accesstoken/test/unittest/PermissionsTest/check_permission_map_test.cpp deleted file mode 100644 index bb184830e..000000000 --- a/interfaces/innerkits/accesstoken/test/unittest/PermissionsTest/check_permission_map_test.cpp +++ /dev/null @@ -1,227 +0,0 @@ -/* - * Copyright (c) 2024 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. - */ - -#include "check_permission_map_test.h" -#include "gtest/gtest.h" -#include -#include -#include -#include -#include -#include -#include -#include - -#include "access_token.h" -#include "cJSON.h" - -#include "permission_def.h" -#include "permission_map.h" - -using namespace testing::ext; -typedef cJSON CJson; -typedef std::unique_ptr> CJsonUnique; -namespace OHOS { -namespace Security { -namespace AccessToken { -namespace { -static const std::string DEFINE_PERMISSION_FILE = "/system/etc/access_token/permission_definitions.json"; -static const std::string SYSTEM_GRANT_DEFINE_PERMISSION = "systemGrantPermissions"; -static const std::string USER_GRANT_DEFINE_PERMISSION = "userGrantPermissions"; -static const std::string PERMISSION_GRANT_MODE_SYSTEM_GRANT = "system_grant"; -constexpr int32_t MAX_NATIVE_CONFIG_FILE_SIZE = 5 * 1024 * 1024; // 5M -constexpr size_t BUFFER_SIZE = 1024; -constexpr uint32_t ACCESS_TOKEN_UID = 3020; -} - -void CheckPermissionMapTest::SetUpTestCase() -{ -} - -void CheckPermissionMapTest::TearDownTestCase() -{ -} - -void CheckPermissionMapTest::SetUp() -{ -} - -void CheckPermissionMapTest::TearDown() -{ -} - -static int32_t GetPermissionGrantMode(const std::string &mode) -{ - if (mode == PERMISSION_GRANT_MODE_SYSTEM_GRANT) { - return AccessToken::GrantMode::SYSTEM_GRANT; - } - return AccessToken::GrantMode::USER_GRANT; -} - -static bool ReadCfgFile(const std::string& file, std::string& rawData) -{ - int32_t selfUid = getuid(); - setuid(ACCESS_TOKEN_UID); - char filePath[PATH_MAX] = {0}; - if (realpath(file.c_str(), filePath) == NULL) { - setuid(selfUid); - return false; - } - int32_t fd = open(filePath, O_RDONLY); - if (fd < 0) { - setuid(selfUid); - return false; - } - struct stat statBuffer; - - if (fstat(fd, &statBuffer) != 0) { - close(fd); - setuid(selfUid); - return false; - } - - if (statBuffer.st_size == 0) { - close(fd); - setuid(selfUid); - return false; - } - if (statBuffer.st_size > MAX_NATIVE_CONFIG_FILE_SIZE) { - close(fd); - setuid(selfUid); - return false; - } - rawData.reserve(statBuffer.st_size); - - char buff[BUFFER_SIZE] = { 0 }; - ssize_t readLen = 0; - while ((readLen = read(fd, buff, BUFFER_SIZE)) > 0) { - rawData.append(buff, readLen); - } - close(fd); - setuid(selfUid); - return true; -} - -void FreeJson(CJson* jsonObj) -{ - cJSON_Delete(jsonObj); - jsonObj = nullptr; -} - -CJsonUnique CreateJsonFromString(const std::string& jsonStr) -{ - if (jsonStr.empty()) { - CJsonUnique aPtr(cJSON_CreateObject(), FreeJson); - return aPtr; - } - CJsonUnique aPtr(cJSON_Parse(jsonStr.c_str()), FreeJson); - return aPtr; -} - -static CJson* GetArrayFromJson(const CJson* jsonObj, const std::string& key) -{ - if (key.empty()) { - return nullptr; - } - - CJson* objValue = cJSON_GetObjectItemCaseSensitive(jsonObj, key.c_str()); - if (objValue != nullptr && cJSON_IsArray(objValue)) { - return objValue; - } - return nullptr; -} - -bool GetStringFromJson(const CJson *jsonObj, const std::string& key, std::string& out) -{ - if (jsonObj == nullptr || key.empty()) { - return false; - } - - cJSON *jsonObjTmp = cJSON_GetObjectItemCaseSensitive(jsonObj, key.c_str()); - if (jsonObjTmp != nullptr && cJSON_IsString(jsonObjTmp)) { - out = cJSON_GetStringValue(jsonObjTmp); - return true; - } - return false; -} - -static bool GetPermissionDefList(const CJsonUnique &json, const std::string& permsRawData, - const std::string& type, std::vector& permDefList) -{ - cJSON *permDefObj = GetArrayFromJson(json.get(), type); - if (permDefObj == nullptr) { - return false; - } - CJson *j = nullptr; - cJSON_ArrayForEach(j, permDefObj) { - PermissionDef result; - GetStringFromJson(j, "name", result.permissionName); - std::string grantModeStr = ""; - GetStringFromJson(j, "grantMode", grantModeStr); - result.grantMode = GetPermissionGrantMode(grantModeStr); - permDefList.emplace_back(result); - } - return true; -} - -static bool ParserPermsRawData(const std::string& permsRawData, - std::vector& permDefList) -{ - CJsonUnique jsonRes = CreateJsonFromString(permsRawData); - if (jsonRes == nullptr) { - return false; - } - - bool ret = GetPermissionDefList(jsonRes, permsRawData, SYSTEM_GRANT_DEFINE_PERMISSION, permDefList); - if (!ret) { - return false; - } - - return GetPermissionDefList(jsonRes, permsRawData, USER_GRANT_DEFINE_PERMISSION, permDefList); -} - -/** - * @tc.name: CheckPermissionMapFuncTest001 - * @tc.desc: Check if permissions in permission_definitions.json are consistent with g_permMap in permission_map.cpp - * @tc.type: FUNC - * @tc.require: - */ -HWTEST_F(CheckPermissionMapTest, CheckPermissionMapFuncTest001, TestSize.Level1) -{ - std::string permsRawData; - EXPECT_TRUE(ReadCfgFile(DEFINE_PERMISSION_FILE, permsRawData)); - - std::vector permDefList; - EXPECT_TRUE(ParserPermsRawData(permsRawData, permDefList)); - - uint32_t opCode; - for (const auto& perm : permDefList) { - // Check if permissions exist - bool isExsit = TransferPermissionToOpcode(perm.permissionName, opCode); - if (!isExsit) { - GTEST_LOG_(INFO) << "permission name is " << perm.permissionName; - } - EXPECT_TRUE(isExsit); - // Check true-user_grant/false-system_grant - if (perm.grantMode == AccessToken::GrantMode::USER_GRANT) { - EXPECT_TRUE(IsUserGrantPermission(perm.permissionName)); - } else if (perm.grantMode == AccessToken::GrantMode::SYSTEM_GRANT) { - EXPECT_FALSE(IsUserGrantPermission(perm.permissionName)); - } - } -} -} // namespace AccessToken -} // namespace Security -} // namespace OHOS \ No newline at end of file diff --git a/interfaces/innerkits/accesstoken/test/unittest/PermissionsTest/check_permission_map_test.h b/interfaces/innerkits/accesstoken/test/unittest/PermissionsTest/check_permission_map_test.h deleted file mode 100644 index f539a211d..000000000 --- a/interfaces/innerkits/accesstoken/test/unittest/PermissionsTest/check_permission_map_test.h +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Copyright (c) 2024 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. - */ - -#ifndef CHECK_PERMISSION_MAP_TEST_H -#define CHECK_PERMISSION_MAP_TEST_H - -#include - -#include "access_token.h" -#include "accesstoken_kit.h" -#include "permission_def.h" -#include "permission_state_full.h" -#include "nocopyable.h" -#include "permission_def.h" - -namespace OHOS { -namespace Security { -namespace AccessToken { -struct PermissionDefParseRet { - PermissionDef permDef; - bool isSuccessful = false; -}; -class CheckPermissionMapTest : public testing::Test { -public: - static void SetUpTestCase(); - static void TearDownTestCase(); - void SetUp(); - void TearDown(); -}; -} // namespace AccessToken -} // namespace Security -} // namespace OHOS -#endif // CHECK_PERMISSION_MAP_TEST_H \ No newline at end of file diff --git a/services/accesstokenmanager/permission_definitions.json b/services/accesstokenmanager/permission_definitions.json index 6003b4329..4f6279b9e 100644 --- a/services/accesstokenmanager/permission_definitions.json +++ b/services/accesstokenmanager/permission_definitions.json @@ -1,5 +1,5 @@ { - "systemGrantPermissions": [ + "definePermissions": [ { "name": "ohos.permission.ACCESS_BIOMETRIC", "grantMode": "system_grant", @@ -708,7 +708,8 @@ "since": 8, "deprecated": "", "provisionEnable": true, - "distributedSceneEnable": false + "distributedSceneEnable": false, + "deviceTypes": ["general"] }, { "name": "ohos.permission.REVOKE_SENSITIVE_PERMISSIONS", @@ -718,7 +719,8 @@ "since": 8, "deprecated": "", "provisionEnable": true, - "distributedSceneEnable": false + "distributedSceneEnable": false, + "deviceTypes": ["general"] }, { "name": "ohos.permission.GET_SENSITIVE_PERMISSIONS", @@ -728,7 +730,8 @@ "since": 8, "deprecated": "", "provisionEnable": true, - "distributedSceneEnable": false + "distributedSceneEnable": false, + "deviceTypes": ["general"] }, { "name": "ohos.permission.SET_TELEPHONY_STATE", @@ -1123,7 +1126,7 @@ { "name": "ohos.permission.ACCESS_CERT_MANAGER_INTERNAL", "grantMode": "system_grant", - "availableLevel": "system_basic", + "availableLevel": "system_core", "availableType": "SYSTEM", "since": 9, "deprecated": "", @@ -4551,9 +4554,7 @@ "deprecated": "", "provisionEnable": true, "distributedSceneEnable": false - } - ], - "userGrantPermissions": [ + }, { "name": "ohos.permission.CUSTOM_SCREEN_CAPTURE", "grantMode": "user_grant", -- Gitee