diff --git a/frameworks/common/include/data_validator.h b/frameworks/common/include/data_validator.h index 5fd826d6e03dd4b79ecfd57b105b119c336aa71c..e0a60c21f5718822ed86a07658ff7b82beeb4fa3 100644 --- a/frameworks/common/include/data_validator.h +++ b/frameworks/common/include/data_validator.h @@ -56,6 +56,7 @@ public: static bool IsPermissionUsedTypeValid(uint32_t type); static bool IsPolicyTypeValid(uint32_t type); static bool IsCallerTypeValid(uint32_t type); + static bool IsNativeCaller(AccessTokenID id); static bool IsHapCaller(AccessTokenID id); static bool IsAclExtendedMapSizeValid(const std::map& aclExtendedMap); static bool IsAclExtendedMapContentValid(const std::string& permissionName, const std::string& value); diff --git a/frameworks/common/src/data_validator.cpp b/frameworks/common/src/data_validator.cpp index 329636c472a986101af356759f6725f14b71f15c..401544d62148ef2edc470f11db19a65bd0f181f7 100644 --- a/frameworks/common/src/data_validator.cpp +++ b/frameworks/common/src/data_validator.cpp @@ -203,6 +203,17 @@ bool DataValidator::IsCallerTypeValid(uint32_t type) return true; } +bool DataValidator::IsNativeCaller(AccessTokenID id) +{ + AccessTokenIDInner* idInner = reinterpret_cast(&id); + ATokenTypeEnum type = static_cast(idInner->type); + if (type != TOKEN_NATIVE) { + LOGE(ATM_DOMAIN, ATM_TAG, "Not Native(%{public}d).", id); + return false; + } + return true; +} + bool DataValidator::IsHapCaller(AccessTokenID id) { AccessTokenIDInner *idInner = reinterpret_cast(&id); diff --git a/interfaces/innerkits/privacy/src/privacy_kit.cpp b/interfaces/innerkits/privacy/src/privacy_kit.cpp index 786a9812b765726bbd9be60b55dc75241f31fcda..73fe5ac8bc363440be39f12e42d755aa93219430 100644 --- a/interfaces/innerkits/privacy/src/privacy_kit.cpp +++ b/interfaces/innerkits/privacy/src/privacy_kit.cpp @@ -86,7 +86,7 @@ int32_t PrivacyKit::AddPermissionUsedRecord(const AddPermParamInfo& info, bool a (!DataValidator::IsPermissionUsedTypeValid(info.type))) { return PrivacyError::ERR_PARAM_INVALID; } - if (!DataValidator::IsHapCaller(info.tokenId)) { + if (!DataValidator::IsHapCaller(info.tokenId) && !DataValidator::IsNativeCaller(info.tokenId)) { return PrivacyError::ERR_PARAM_INVALID; } @@ -128,7 +128,7 @@ int32_t PrivacyKit::StartUsingPermission(AccessTokenID tokenID, const std::strin (!DataValidator::IsPermissionUsedTypeValid(type))) { return PrivacyError::ERR_PARAM_INVALID; } - if (!DataValidator::IsHapCaller(tokenID)) { + if (!DataValidator::IsHapCaller(tokenID) && !DataValidator::IsNativeCaller(tokenID)) { return PrivacyError::ERR_PARAM_INVALID; } return PrivacyManagerClient::GetInstance().StartUsingPermission(tokenID, pid, permissionName, type); @@ -142,7 +142,7 @@ int32_t PrivacyKit::StartUsingPermission(AccessTokenID tokenID, const std::strin (!DataValidator::IsPermissionUsedTypeValid(type))) { return PrivacyError::ERR_PARAM_INVALID; } - if (!DataValidator::IsHapCaller(tokenID)) { + if (!DataValidator::IsHapCaller(tokenID) && !DataValidator::IsNativeCaller(tokenID)) { return PrivacyError::ERR_PARAM_INVALID; } return PrivacyManagerClient::GetInstance().StartUsingPermission(tokenID, pid, permissionName, callback, type); @@ -153,7 +153,7 @@ int32_t PrivacyKit::StopUsingPermission(AccessTokenID tokenID, const std::string if (!DataValidator::IsTokenIDValid(tokenID) || !DataValidator::IsPermissionNameValid(permissionName)) { return PrivacyError::ERR_PARAM_INVALID; } - if (!DataValidator::IsHapCaller(tokenID)) { + if (!DataValidator::IsHapCaller(tokenID) && !DataValidator::IsNativeCaller(tokenID)) { return PrivacyError::ERR_PARAM_INVALID; } return PrivacyManagerClient::GetInstance().StopUsingPermission(tokenID, pid, permissionName); @@ -164,7 +164,7 @@ int32_t PrivacyKit::RemovePermissionUsedRecords(AccessTokenID tokenID) if (!DataValidator::IsTokenIDValid(tokenID)) { return PrivacyError::ERR_PARAM_INVALID; } - if (!DataValidator::IsHapCaller(tokenID)) { + if (!DataValidator::IsHapCaller(tokenID) && !DataValidator::IsNativeCaller(tokenID)) { return PrivacyError::ERR_PARAM_INVALID; } return PrivacyManagerClient::GetInstance().RemovePermissionUsedRecords(tokenID); diff --git a/interfaces/innerkits/privacy/test/unittest/src/privacy_kit_test.cpp b/interfaces/innerkits/privacy/test/unittest/src/privacy_kit_test.cpp index f6ca7b1ced9fc2d1ddc14282eca3a78d3707ede1..8e4ca78bfd2c400632b99cde8bbf073ef4db5fc8 100644 --- a/interfaces/innerkits/privacy/test/unittest/src/privacy_kit_test.cpp +++ b/interfaces/innerkits/privacy/test/unittest/src/privacy_kit_test.cpp @@ -48,6 +48,7 @@ using namespace OHOS::Security::AccessToken; const static int32_t RET_NO_ERROR = 0; static const uint32_t ACCESS_TOKEN_UID = 3020; static AccessTokenID g_nativeToken = 0; +static AccessTokenID g_shellToken = 0; static MockHapToken* g_mock = nullptr; #ifdef AUDIO_FRAMEWORK_ENABLE static bool g_isMicMute = false; @@ -245,6 +246,7 @@ void PrivacyKitTest::SetUpTestCase() g_mock = new (std::nothrow) MockHapToken("PrivacyKitTest", reqPerm, true); g_nativeToken = PrivacyTestCommon::GetNativeTokenIdFromProcess("privacy_service"); + g_shellToken = PrivacyTestCommon::GetNativeTokenIdFromProcess("hdcd"); DeleteTestToken(); #ifdef AUDIO_FRAMEWORK_ENABLE @@ -738,6 +740,18 @@ HWTEST_F(PrivacyKitTest, RemovePermissionUsedRecords003, TestSize.Level0) ASSERT_EQ(PrivacyError::ERR_NOT_SYSTEM_APP, PrivacyKit::RemovePermissionUsedRecords(tokenID)); } +/** + * @tc.name: RemovePermissionUsedRecords004 + * @tc.desc: cannot RemovePermissionUsedRecords function test. + * @tc.type: FUNC + * @tc.require: + */ +HWTEST_F(PrivacyKitTest, RemovePermissionUsedRecords004, TestSize.Level0) +{ + EXPECT_EQ(RET_SUCCESS, PrivacyKit::RemovePermissionUsedRecords(g_nativeToken)); + EXPECT_EQ(PrivacyError::ERR_PARAM_INVALID, PrivacyKit::RemovePermissionUsedRecords(g_shellToken)); +} + /** * @tc.name: GetPermissionUsedRecords001 * @tc.desc: cannot GetPermissionUsedRecords with invalid query time and flag. @@ -1841,6 +1855,46 @@ HWTEST_F(PrivacyKitTest, StartUsingPermission014, TestSize.Level0) PrivacyKit::StartUsingPermission(g_tokenIdE, permissionName, callbackPtr)); } +/** + * @tc.name: StartUsingPermission015 + * @tc.desc: StartUsingPermission function test. + * @tc.type: FUNC + * @tc.require: + */ +HWTEST_F(PrivacyKitTest, StartUsingPermission015, TestSize.Level0) +{ + std::string permissionName = "ohos.permission.CAMERA"; + auto callbackPtr = std::make_shared(); + + EXPECT_EQ(PrivacyError::ERR_PARAM_INVALID, + PrivacyKit::StartUsingPermission(g_nativeToken, permissionName, callbackPtr)); + + permissionName = "ohos.permission.MICROPHONE"; + EXPECT_EQ(PrivacyError::ERR_PARAM_INVALID, + PrivacyKit::StartUsingPermission(g_nativeToken, permissionName, callbackPtr)); + + EXPECT_EQ(PrivacyError::ERR_PARAM_INVALID, + PrivacyKit::StartUsingPermission(g_shellToken, permissionName, callbackPtr)); +} + +/** + * @tc.name: StartUsingPermission016 + * @tc.desc: StartUsingPermission caller is shell. + * @tc.type: FUNC + * @tc.require: + */ +HWTEST_F(PrivacyKitTest, StartUsingPermission016, TestSize.Level0) +{ + std::string permissionName = "ohos.permission.CAMERA"; + + EXPECT_EQ(PrivacyError::ERR_PARAM_INVALID, PrivacyKit::StartUsingPermission(g_nativeToken, permissionName)); + + permissionName = "ohos.permission.MICROPHONE"; + EXPECT_EQ(PrivacyError::ERR_PARAM_INVALID, PrivacyKit::StartUsingPermission(g_nativeToken, permissionName)); + + EXPECT_EQ(PrivacyError::ERR_PARAM_INVALID, PrivacyKit::StartUsingPermission(g_shellToken, permissionName)); +} + /** * @tc.name: StopUsingPermission001 * @tc.desc: StopUsingPermission with invalid tokenId or permission. @@ -1899,7 +1953,7 @@ HWTEST_F(PrivacyKitTest, StopUsingPermission004, TestSize.Level0) /** * @tc.name: StopUsingPermission005 - * @tc.desc: stop use whith native token + * @tc.desc: stop use with native token * @tc.type: FUNC * @tc.require: issueI5SZHG */ @@ -1953,6 +2007,24 @@ HWTEST_F(PrivacyKitTest, StopUsingPermission007, TestSize.Level0) ASSERT_EQ(1, result.bundleRecords[0].permissionRecords[0].accessCount); } +/** + * @tc.name: StopUsingPermission008 + * @tc.desc: StopUsingPermission test with shell tokenid. + * @tc.type: FUNC + * @tc.require: + */ +HWTEST_F(PrivacyKitTest, StopUsingPermission008, TestSize.Level0) +{ + std::string permissionName = "ohos.permission.CAMERA"; + + EXPECT_EQ(PrivacyError::ERR_PARAM_INVALID, PrivacyKit::StopUsingPermission(g_nativeToken, permissionName)); + + permissionName = "ohos.permission.MICROPHONE"; + EXPECT_EQ(PrivacyError::ERR_PARAM_INVALID, PrivacyKit::StopUsingPermission(g_nativeToken, permissionName)); + + EXPECT_EQ(PrivacyError::ERR_PARAM_INVALID, PrivacyKit::StopUsingPermission(g_shellToken, permissionName)); +} + class TestCallBack1 : public StateChangeCallbackStub { public: TestCallBack1() = default; @@ -2370,6 +2442,29 @@ HWTEST_F(PrivacyKitTest, AddPermissionUsedRecord018, TestSize.Level0) ASSERT_EQ(PrivacyError::ERR_PARAM_INVALID, PrivacyKit::AddPermissionUsedRecord(info)); // add invalid used type } +/** + * @tc.name: AddPermissionUsedRecord019 + * @tc.desc: Test AddPermissionUsedRecord with shell token + * @tc.type: FUNC + * @tc.require: + */ +HWTEST_F(PrivacyKitTest, AddPermissionUsedRecord019, TestSize.Level0) +{ + AddPermParamInfo info; + info.tokenId = g_nativeToken; + info.permissionName = "ohos.permission.CAMERA"; + info.successCount = 1; + info.failCount = 0; + info.type = NORMAL_TYPE; + EXPECT_EQ(PrivacyError::ERR_PARAM_INVALID, PrivacyKit::AddPermissionUsedRecord(info)); + + info.permissionName = "ohos.permission.MICROPHONE"; + EXPECT_EQ(PrivacyError::ERR_PARAM_INVALID, PrivacyKit::AddPermissionUsedRecord(info)); + + info.tokenId = g_shellToken; + EXPECT_EQ(PrivacyError::ERR_PARAM_INVALID, PrivacyKit::AddPermissionUsedRecord(info)); +} + /** * @tc.name: GetPermissionUsedTypeInfos001 * @tc.desc: Test GetPermissionUsedTypeInfos with default input diff --git a/services/privacymanager/BUILD.gn b/services/privacymanager/BUILD.gn index 3918d3409a19160dc007a11936a9b72c03ecb088..1d5fad4247841ec7edc598179585ff557fd3dd1a 100644 --- a/services/privacymanager/BUILD.gn +++ b/services/privacymanager/BUILD.gn @@ -169,6 +169,7 @@ if (is_standard_system && ability_base_enable == true) { "src/active/perm_active_status_change_callback_proxy.cpp", "src/active/state_change_callback_proxy.cpp", "src/common/constant.cpp", + "src/common/access_token_helper.cpp", "src/database/data_translator.cpp", "src/database/permission_used_record_db.cpp", "src/database/privacy_field_const.cpp", diff --git a/services/privacymanager/include/common/access_token_helper.h b/services/privacymanager/include/common/access_token_helper.h new file mode 100644 index 0000000000000000000000000000000000000000..746ddb1ad07ff8e98ad49d9dd2c5ae9627947fc6 --- /dev/null +++ b/services/privacymanager/include/common/access_token_helper.h @@ -0,0 +1,32 @@ +/* + * 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. + */ + +#ifndef ACCESS_TOKEN_ACCESS_TOKEN_HELPER_H +#define ACCESS_TOKEN_ACCESS_TOKEN_HELPER_H + +#include "accesstoken_kit.h" + +namespace OHOS { +namespace Security { +namespace AccessToken { + +class AccessTokenHelper { +public: + static int32_t VerifyAccessToken(const AccessToken::AccessTokenID& callertoken, const std::string& permission); +}; +} // namespace AccessToken +} // namespace Security +} // namespace OHOS +#endif // ACCESS_TOKEN_ACCESS_TOKEN_HELPER_H \ No newline at end of file diff --git a/services/privacymanager/include/record/permission_record_manager.h b/services/privacymanager/include/record/permission_record_manager.h index 17f738733380a00281e40aa39a4eaf0cbe49d2e1..cb987f154c462c0576c1a5cf4c988389f5701897 100644 --- a/services/privacymanager/include/record/permission_record_manager.h +++ b/services/privacymanager/include/record/permission_record_manager.h @@ -133,6 +133,7 @@ private: bool IsAllowedUsingMicrophone(AccessTokenID tokenId, int32_t pid); bool CheckPermissionUsedRecordToggleStatus(int32_t userID); + bool VerifyNativeRecordPermission(const std::string& permissionName, const AccessTokenID& tokenId); bool UpdatePermUsedRecToggleStatusMap(int32_t userID, bool status); void UpdatePermUsedRecToggleStatusMapFromDb(); bool AddOrUpdateUsedStatusIfNeeded(int32_t userID, bool status); diff --git a/services/privacymanager/src/common/access_token_helper.cpp b/services/privacymanager/src/common/access_token_helper.cpp new file mode 100644 index 0000000000000000000000000000000000000000..4687c40130fad0ad9c381cbd8375fbf06f19024b --- /dev/null +++ b/services/privacymanager/src/common/access_token_helper.cpp @@ -0,0 +1,28 @@ +/* + * 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. + */ + +#include "access_token_helper.h" + +namespace OHOS { +namespace Security { +namespace AccessToken { +int32_t AccessTokenHelper::VerifyAccessToken(const AccessTokenID& callerToken, + const std::string& permission) +{ + return AccessTokenKit::VerifyAccessToken(callerToken, permission); +} +} // namespace AccessToken +} // namespace Security +} // namespace OHOS \ No newline at end of file diff --git a/services/privacymanager/src/record/permission_record_manager.cpp b/services/privacymanager/src/record/permission_record_manager.cpp index 35c8203079e250998402e10d681ec94234656977..ff8ef648e9878ae161403f797ce3f409b3ad4aa9 100644 --- a/services/privacymanager/src/record/permission_record_manager.cpp +++ b/services/privacymanager/src/record/permission_record_manager.cpp @@ -23,6 +23,7 @@ #include "ability_manager_access_loader.h" #endif #include "access_token.h" +#include "access_token_helper.h" #include "accesstoken_kit.h" #include "accesstoken_common_log.h" #include "active_status_callback_manager.h" @@ -415,8 +416,33 @@ bool PermissionRecordManager::CheckPermissionUsedRecordToggleStatus(int32_t user return true; } +bool PermissionRecordManager::VerifyNativeRecordPermission( + const std::string& permissionName, const AccessTokenID& tokenId) +{ + bool isGranted = false; + if (permissionName == CAMERA_PERMISSION_NAME) { + isGranted = (AccessTokenHelper::VerifyAccessToken( + tokenId, "ohos.permission.CAMERA_BACKGROUND") == PERMISSION_GRANTED); + LOGI(PRI_DOMAIN, PRI_TAG, "Native tokenId %{public}d, isGranted %{public}d, permission %{public}s.", + tokenId, isGranted, permissionName.c_str()); + return isGranted; + } else if (permissionName == MICROPHONE_PERMISSION_NAME) { + isGranted = (AccessTokenHelper::VerifyAccessToken( + tokenId, "ohos.permission.MICROPHONE_BACKGROUND") == PERMISSION_GRANTED); + LOGI(PRI_DOMAIN, PRI_TAG, "Native tokenId %{public}d, isGranted %{public}d, permission %{public}s.", + tokenId, isGranted, permissionName.c_str()); + return isGranted; + } + LOGE(PRI_DOMAIN, PRI_TAG, "Invalid permission %{public}s.", permissionName.c_str()); + return isGranted; +} + int32_t PermissionRecordManager::AddPermissionUsedRecord(const AddPermParamInfo& info) { + if (AccessTokenKit::GetTokenTypeFlag(info.tokenId) == TOKEN_NATIVE) { + return VerifyNativeRecordPermission( + info.permissionName, info.tokenId) ? Constant::SUCCESS : PrivacyError::ERR_PARAM_INVALID; + } HapTokenInfo tokenInfo; if (AccessTokenKit::GetHapTokenInfo(info.tokenId, tokenInfo) != Constant::SUCCESS) { LOGE(PRI_DOMAIN, PRI_TAG, "Invalid tokenId(%{public}d).", info.tokenId); @@ -1295,6 +1321,12 @@ int32_t PermissionRecordManager::StartUsingPermission(const PermissionUsedTypeIn LOGI(PRI_DOMAIN, PRI_TAG, "Id: %{public}u, pid: %{public}d, perm: %{public}s, type: %{public}d, callerPid: %{public}d.", tokenId, info.pid, permissionName.c_str(), info.type, callerPid); + + if (AccessTokenKit::GetTokenTypeFlag(tokenId) == TOKEN_NATIVE) { + return VerifyNativeRecordPermission( + permissionName, tokenId) ? Constant::SUCCESS : PrivacyError::ERR_PARAM_INVALID; + } + if (AccessTokenKit::GetTokenTypeFlag(tokenId) != TOKEN_HAP) { LOGD(PRI_DOMAIN, PRI_TAG, "Not hap(%{public}d).", tokenId); return PrivacyError::ERR_PARAM_INVALID; @@ -1329,6 +1361,12 @@ int32_t PermissionRecordManager::StartUsingPermission(const PermissionUsedTypeIn LOGI(PRI_DOMAIN, PRI_TAG, "Id: %{public}u, pid: %{public}d, perm: %{public}s, type: %{public}d, callerPid: %{public}d.", tokenId, info.pid, permissionName.c_str(), info.type, callerPid); + + if (AccessTokenKit::GetTokenTypeFlag(tokenId) == TOKEN_NATIVE) { + return VerifyNativeRecordPermission( + permissionName, tokenId) ? Constant::SUCCESS : PrivacyError::ERR_PARAM_INVALID; + } + if ((permissionName != CAMERA_PERMISSION_NAME) || (AccessTokenKit::GetTokenTypeFlag(tokenId) != TOKEN_HAP)) { LOGD(PRI_DOMAIN, PRI_TAG, "Token(%{public}u), perm(%{public}s).", tokenId, permissionName.c_str()); return PrivacyError::ERR_PARAM_INVALID; @@ -1368,6 +1406,11 @@ int32_t PermissionRecordManager::StartUsingPermission(const PermissionUsedTypeIn int32_t PermissionRecordManager::StopUsingPermission( AccessTokenID tokenId, int32_t pid, const std::string& permissionName, int32_t callerPid) { + if (AccessTokenKit::GetTokenTypeFlag(tokenId) == TOKEN_NATIVE) { + return VerifyNativeRecordPermission( + permissionName, tokenId) ? Constant::SUCCESS : PrivacyError::ERR_PARAM_INVALID; + } + if (AccessTokenKit::GetTokenTypeFlag(tokenId) != TOKEN_HAP) { LOGD(PRI_DOMAIN, PRI_TAG, "Not hap(%{public}d).", tokenId); return PrivacyError::ERR_PARAM_INVALID; @@ -1451,6 +1494,10 @@ bool PermissionRecordManager::IsAllowedUsingMicrophone(AccessTokenID tokenId, in bool PermissionRecordManager::IsAllowedUsingPermission(AccessTokenID tokenId, const std::string& permissionName, int32_t pid) { + if (AccessTokenKit::GetTokenTypeFlag(tokenId) == TOKEN_NATIVE) { + return VerifyNativeRecordPermission(permissionName, tokenId); + } + if (AccessTokenKit::GetTokenTypeFlag(tokenId) != TOKEN_HAP) { LOGD(PRI_DOMAIN, PRI_TAG, "Id(%{public}d) is not hap.", tokenId); return false; diff --git a/services/privacymanager/test/BUILD.gn b/services/privacymanager/test/BUILD.gn index e903da5f5292f47ea3cd0a0b1a94fe3741dc6d26..7539ca481f0f74d62fac347c7b72c97ecb0acda9 100644 --- a/services/privacymanager/test/BUILD.gn +++ b/services/privacymanager/test/BUILD.gn @@ -15,6 +15,7 @@ group("unittest") { testonly = true deps = [ "coverage:libprivacy_manager_service_coverage_test", + "mock:libprivacy_manager_service_mock_test", "unittest:libprivacy_manager_service_standard_test", ] } diff --git a/services/privacymanager/test/coverage/BUILD.gn b/services/privacymanager/test/coverage/BUILD.gn index 76b78de9710f3fa122cacb7d249516943986e046..f770637daf06fe65945bca81ec9d86140685bb49 100644 --- a/services/privacymanager/test/coverage/BUILD.gn +++ b/services/privacymanager/test/coverage/BUILD.gn @@ -58,6 +58,7 @@ if (is_standard_system && ability_base_enable == true) { "../../src/active/perm_active_status_change_callback_proxy.cpp", "../../src/active/state_change_callback_proxy.cpp", "../../src/common/constant.cpp", + "../../src/common/access_token_helper.cpp", "../../src/database/data_translator.cpp", "../../src/database/permission_used_record_db.cpp", "../../src/database/privacy_field_const.cpp", diff --git a/services/privacymanager/test/mock/BUILD.gn b/services/privacymanager/test/mock/BUILD.gn new file mode 100644 index 0000000000000000000000000000000000000000..d4a7a6416362d2a467b1b8f1e0e2ad91d009e5f6 --- /dev/null +++ b/services/privacymanager/test/mock/BUILD.gn @@ -0,0 +1,139 @@ +# Copyright (c) 2022-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("//build/test.gni") +import("../../../../access_token.gni") + +if (is_standard_system && ability_base_enable == true) { + ohos_unittest("libprivacy_manager_service_mock_test") { + subsystem_name = "accesscontrol" + module_out_path = module_output_path_unittest_privacy + sanitize = { + cfi = true + cfi_cross_dso = true + debug = false + } + branch_protector_ret = "pac_ret" + + include_dirs = [ + "${access_token_path}/frameworks/common/include", + "${access_token_path}/frameworks/privacy/include", + "${access_token_path}/interfaces/innerkits/accesstoken/include", + "${access_token_path}/interfaces/innerkits/privacy/include", + "${access_token_path}/interfaces/innerkits/nativetoken/include", + "${access_token_path}/interfaces/innerkits/privacy/test/unittest/src", + "${access_token_path}/interfaces/innerkits/privacy/src", + "${access_token_path}/services/common/app_manager/include", + "${access_token_path}/services/common/json_parse/include", + "${access_token_path}/services/common/database/include", + "${access_token_path}/services/common/handler/include", + "${access_token_path}/services/common/libraryloader/include", + "${access_token_path}/services/common/screenlock_manager/include", + "${access_token_path}/services/common/utils/include", + "${access_token_path}/services/privacymanager/include/active", + "${access_token_path}/services/privacymanager/include/common", + "${access_token_path}/services/privacymanager/include/database", + "${access_token_path}/services/privacymanager/include/record", + "${access_token_path}/services/privacymanager/include/service", + "${access_token_path}/services/privacymanager/include/proxy", + "${access_token_path}/services/privacymanager/include/sensitive/audio_manager", + "${access_token_path}/services/privacymanager/include/sensitive/camera_manager", + "${access_token_path}/services/accesstokenmanager/main/cpp/include/token", + ] + + sources = [ + "${access_token_path}/interfaces/innerkits/privacy/test/unittest/src/privacy_test_common.cpp", + "${access_token_path}/services/common/libraryloader/src/libraryloader.cpp", + "../../src/active/active_status_callback_manager.cpp", + "../../src/active/perm_active_status_callback_death_recipient.cpp", + "../../src/active/perm_active_status_change_callback_proxy.cpp", + "../../src/active/state_change_callback_proxy.cpp", + "../../src/common/constant.cpp", + "../../src/database/data_translator.cpp", + "../../src/database/permission_used_record_db.cpp", + "../../src/database/privacy_field_const.cpp", + "../../src/proxy/privacy_manager_proxy_death_param.cpp", + "../../src/record/on_permission_used_record_callback_proxy.cpp", + "../../src/record/permission_record.cpp", + "../../src/record/permission_record_manager.cpp", + "../../src/record/permission_record_set.cpp", + "../../src/sensitive/audio_manager/audio_manager_adapter.cpp", + "../../src/sensitive/camera_manager/camera_manager_adapter.cpp", + "../../src/service/privacy_manager_service.cpp", + "access_token_helper_mock.cpp", + "permission_record_manager_mock_test.cpp", + ] + + cflags_cc = [ "-DHILOG_ENABLE" ] + + configs = [ + "${access_token_path}/config:coverage_flags", + "${access_token_path}/services/privacymanager:privacy_manager_gen_config", + ] + + deps = [ + "${access_token_path}/frameworks/common:accesstoken_common_cxx", + "${access_token_path}/frameworks/privacy:privacy_communication_adapter_cxx", + "${access_token_path}/interfaces/innerkits/accesstoken:libaccesstoken_sdk", + "${access_token_path}/interfaces/innerkits/accesstoken:libtokenid_sdk", + "${access_token_path}/interfaces/innerkits/nativetoken:libnativetoken_shared", + "${access_token_path}/interfaces/innerkits/privacy:libprivacy_sdk", + "${access_token_path}/interfaces/innerkits/token_setproc:libtokensetproc_shared", + "${access_token_path}/services/common:accesstoken_service_common", + "${access_token_path}/services/common/proxy_death:proxy_death_handler", + "${access_token_path}/services/common/proxy_death:proxy_death_stub", + "${access_token_path}/services/privacymanager:privacy_manager_service", + "${access_token_path}/services/privacymanager:privacy_manager_stub", + ] + + external_deps = [ + "ability_base:want", + "access_token:libaccesstoken_sdk", + "c_utils:utils", + "googletest:gtest_main", + "hilog:libhilog", + "hisysevent:libhisysevent", + "init:libbegetutil", + "ipc:ipc_core", + "safwk:system_ability_fwk", + "samgr:samgr_proxy", + "sqlite:sqlite", + ] + + if (audio_framework_enable) { + cflags_cc += [ "-DAUDIO_FRAMEWORK_ENABLE" ] + external_deps += [ "audio_framework:audio_client" ] + } + + if (camera_framework_enable) { + cflags_cc += [ "-DCAMERA_FRAMEWORK_ENABLE" ] + external_deps += [ "camera_framework:camera_framework" ] + } + + if (eventhandler_enable == true) { + cflags_cc += [ "-DEVENTHANDLER_ENABLE" ] + external_deps += [ "eventhandler:libeventhandler" ] + } + if (common_event_service_enable) { + cflags_cc += [ "-DCOMMON_EVENT_SERVICE_ENABLE" ] + external_deps += [ "common_event_service:cesfwk_innerkits" ] + sources += [ "../../src/common/privacy_common_event_subscriber.cpp" ] + } + + if (access_token_app_security_privacy_service_enable) { + cflags_cc += [ "-DAPP_SECURITY_PRIVACY_SERVICE" ] + } else { + include_dirs += [ "${access_token_path}/services/common/ability_manager/include" ] + } + } +} \ No newline at end of file diff --git a/services/privacymanager/test/mock/access_token_helper_mock.cpp b/services/privacymanager/test/mock/access_token_helper_mock.cpp new file mode 100644 index 0000000000000000000000000000000000000000..b363b9f93c19f2b5ecf62faa5a25f0d35539b874 --- /dev/null +++ b/services/privacymanager/test/mock/access_token_helper_mock.cpp @@ -0,0 +1,40 @@ +/* + * 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. + */ + +#include "access_token_helper.h" + +namespace OHOS { +namespace Security { +namespace AccessToken { +namespace { +static constexpr int32_t NATIVE_WITH_PERM = 672000000; +std::string BACKGROUND_MIC_PERM = "ohos.permission.MICROPHONE_BACKGROUND"; +std::string BACKGROUND_CAM_PERM = "ohos.permission.CAMERA_BACKGROUND"; +} +int32_t AccessTokenHelper::VerifyAccessToken(const AccessTokenID& callerToken, + const std::string& permission) +{ + if (AccessTokenKit::GetTokenTypeFlag(callerToken) == TOKEN_NATIVE && + (permission == BACKGROUND_MIC_PERM || permission == BACKGROUND_CAM_PERM)) { + if (callerToken > NATIVE_WITH_PERM) { + return PERMISSION_GRANTED; + } + return PERMISSION_DENIED; + } + return AccessTokenKit::VerifyAccessToken(callerToken, permission); +} +} // namespace AccessToken +} // namespace Security +} // namespace OHOS \ No newline at end of file diff --git a/services/privacymanager/test/mock/permission_record_manager_mock_test.cpp b/services/privacymanager/test/mock/permission_record_manager_mock_test.cpp new file mode 100644 index 0000000000000000000000000000000000000000..9d72a78440cbb688db95307b7ebaa7199cc014a4 --- /dev/null +++ b/services/privacymanager/test/mock/permission_record_manager_mock_test.cpp @@ -0,0 +1,289 @@ +/* + * Copyright (c) 2022-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. + */ + +#include +#include +#include + +#include "access_token.h" +#include "accesstoken_kit.h" + +#include "constant.h" +#include "permission_record.h" +#include "permission_used_type_info.h" +#include "permission_used_request.h" +#include "permission_used_result.h" +#define private public +#include "permission_record_manager.h" +#include "privacy_manager_service.h" +#undef private +#include "privacy_error.h" +#include "privacy_field_const.h" +#include "privacy_kit.h" +#include "privacy_test_common.h" + +using namespace testing; +using namespace testing::ext; +using namespace OHOS; + +namespace OHOS { +namespace Security { +namespace AccessToken { +namespace { +static constexpr int32_t PID = -1; +static constexpr int32_t CALLER_PID = 11; +static constexpr int32_t NATIVE_TOKEN_WITH_PERM = 672000001; +static constexpr int32_t NATIVE_TOKEN_WITHOUT_PERM = 671999999; +static AccessTokenID g_selfTokenId = 0; +static AccessTokenID g_shellToken = 0; +static MockNativeToken* g_mock = nullptr; +static const char* INVALID_PERMISSION_NAME = "ohos.permission.READ_MEDIA"; +constexpr const char* CAMERA_PERMISSION_NAME = "ohos.permission.CAMERA"; +constexpr const char* MICROPHONE_PERMISSION_NAME = "ohos.permission.MICROPHONE"; +} +class PermissionRecordManagerMockTest : public testing::Test { +public: + static void SetUpTestCase(); + static void TearDownTestCase(); + void SetUp(); + void TearDown(); +}; + +void PermissionRecordManagerMockTest::SetUpTestCase() +{ + g_selfTokenId = GetSelfTokenID(); + PrivacyTestCommon::SetTestEvironment(g_selfTokenId); + g_mock = new (std::nothrow) MockNativeToken("privacy_service"); + + DelayedSingleton::GetInstance()->Initialize(); + PermissionRecordManager::GetInstance().Init(); + + g_shellToken = PrivacyTestCommon::GetNativeTokenIdFromProcess("hdcd"); +} + +void PermissionRecordManagerMockTest::TearDownTestCase() +{ + PrivacyTestCommon::ResetTestEvironment(); + if (g_mock != nullptr) { + delete g_mock; + g_mock = nullptr; + } +} + +void PermissionRecordManagerMockTest::SetUp() +{ + PermissionRecordManager::GetInstance().Init(); + PermissionRecordManager::GetInstance().Register(); +} + +void PermissionRecordManagerMockTest::TearDown() +{ +} + +static PermissionUsedTypeInfo MakeInfo(AccessTokenID tokenId, int32_t pid, const std::string& permission, + PermissionUsedType type = PermissionUsedType::NORMAL_TYPE) +{ + PermissionUsedTypeInfo info = { + .tokenId = tokenId, + .pid = pid, + .permissionName = permission, + .type = type + }; + return info; +} + +/* + * @tc.name: AddPermissionUsedRecordMockTest001 + * @tc.desc: PermissionRecordManager::AddPermissionUsedRecord function test + * @tc.type: FUNC + * @tc.require: + */ +HWTEST_F(PermissionRecordManagerMockTest, AddPermissionUsedRecordMockTest001, TestSize.Level0) +{ + AddPermParamInfo info; + info.tokenId = NATIVE_TOKEN_WITH_PERM; + info.permissionName = INVALID_PERMISSION_NAME; + info.successCount = 1; + info.failCount = 0; + info.type = NORMAL_TYPE; + + EXPECT_EQ(PrivacyError::ERR_PARAM_INVALID, PermissionRecordManager::GetInstance().AddPermissionUsedRecord(info)); + + info.permissionName = MICROPHONE_PERMISSION_NAME; + EXPECT_EQ(Constant::SUCCESS, PermissionRecordManager::GetInstance().AddPermissionUsedRecord(info)); + + PermissionUsedRequest request; + request.tokenId = NATIVE_TOKEN_WITH_PERM; + PermissionUsedResult result; + + EXPECT_EQ(Constant::SUCCESS, PermissionRecordManager::GetInstance().GetPermissionUsedRecords(request, result)); + + EXPECT_EQ(result.bundleRecords.size(), 0); + + info.tokenId = NATIVE_TOKEN_WITHOUT_PERM; + EXPECT_EQ(PrivacyError::ERR_PARAM_INVALID, PermissionRecordManager::GetInstance().AddPermissionUsedRecord(info)); + + info.permissionName = CAMERA_PERMISSION_NAME; + EXPECT_EQ(PrivacyError::ERR_PARAM_INVALID, PermissionRecordManager::GetInstance().AddPermissionUsedRecord(info)); + + info.tokenId = NATIVE_TOKEN_WITH_PERM; + EXPECT_EQ(Constant::SUCCESS, PermissionRecordManager::GetInstance().AddPermissionUsedRecord(info)); + + request.tokenId = NATIVE_TOKEN_WITH_PERM; + EXPECT_EQ(Constant::SUCCESS, PermissionRecordManager::GetInstance().GetPermissionUsedRecords(request, result)); + + EXPECT_EQ(result.bundleRecords.size(), 0); + + info.tokenId = g_shellToken; + EXPECT_EQ(PrivacyError::ERR_TOKENID_NOT_EXIST, + PermissionRecordManager::GetInstance().AddPermissionUsedRecord(info)); +} + +/* + * @tc.name: StartUsingPermissionMockTest001 + * @tc.desc: StartUsingPermission function test + * @tc.type: FUNC + * @tc.require: + */ +HWTEST_F(PermissionRecordManagerMockTest, StartUsingPermissionMockTest001, TestSize.Level0) +{ + std::string permissionName = INVALID_PERMISSION_NAME; + AccessTokenID tokenId = NATIVE_TOKEN_WITH_PERM; + + EXPECT_EQ(PrivacyError::ERR_PARAM_INVALID, PermissionRecordManager::GetInstance().StartUsingPermission( + MakeInfo(tokenId, PID, permissionName), CALLER_PID)); + + permissionName = MICROPHONE_PERMISSION_NAME; + EXPECT_EQ(Constant::SUCCESS, PermissionRecordManager::GetInstance().StartUsingPermission( + MakeInfo(tokenId, PID, permissionName), CALLER_PID)); + + tokenId = NATIVE_TOKEN_WITHOUT_PERM; + EXPECT_EQ(PrivacyError::ERR_PARAM_INVALID, PermissionRecordManager::GetInstance().StartUsingPermission( + MakeInfo(tokenId, PID, permissionName), CALLER_PID)); + + permissionName = CAMERA_PERMISSION_NAME; + EXPECT_EQ(PrivacyError::ERR_PARAM_INVALID, PermissionRecordManager::GetInstance().StartUsingPermission( + MakeInfo(tokenId, PID, permissionName), CALLER_PID)); + + tokenId = NATIVE_TOKEN_WITH_PERM; + EXPECT_EQ(Constant::SUCCESS, PermissionRecordManager::GetInstance().StartUsingPermission( + MakeInfo(tokenId, PID, permissionName), CALLER_PID)); + + tokenId = g_shellToken; + EXPECT_EQ(PrivacyError::ERR_PARAM_INVALID, PermissionRecordManager::GetInstance().StartUsingPermission( + MakeInfo(tokenId, PID, permissionName), CALLER_PID)); +} + +/* + * @tc.name: StartUsingPermissionMockTest002 + * @tc.desc: StartUsingPermission function test + * @tc.type: FUNC + * @tc.require: + */ +HWTEST_F(PermissionRecordManagerMockTest, StartUsingPermissionMockTest002, TestSize.Level0) +{ + std::string permissionName = INVALID_PERMISSION_NAME; + AccessTokenID tokenId = NATIVE_TOKEN_WITH_PERM; + + EXPECT_EQ(PrivacyError::ERR_PARAM_INVALID, PermissionRecordManager::GetInstance().StartUsingPermission( + MakeInfo(tokenId, PID, permissionName), nullptr, CALLER_PID)); + + permissionName = MICROPHONE_PERMISSION_NAME; + EXPECT_EQ(Constant::SUCCESS, PermissionRecordManager::GetInstance().StartUsingPermission( + MakeInfo(tokenId, PID, permissionName), nullptr, CALLER_PID)); + + tokenId = NATIVE_TOKEN_WITHOUT_PERM; + EXPECT_EQ(PrivacyError::ERR_PARAM_INVALID, PermissionRecordManager::GetInstance().StartUsingPermission( + MakeInfo(tokenId, PID, permissionName), nullptr, CALLER_PID)); + + permissionName = CAMERA_PERMISSION_NAME; + EXPECT_EQ(PrivacyError::ERR_PARAM_INVALID, PermissionRecordManager::GetInstance().StartUsingPermission( + MakeInfo(tokenId, PID, permissionName), nullptr, CALLER_PID)); + + tokenId = NATIVE_TOKEN_WITH_PERM; + EXPECT_EQ(Constant::SUCCESS, PermissionRecordManager::GetInstance().StartUsingPermission( + MakeInfo(tokenId, PID, permissionName), nullptr, CALLER_PID)); + + tokenId = g_shellToken; + EXPECT_EQ(PrivacyError::ERR_PARAM_INVALID, PermissionRecordManager::GetInstance().StartUsingPermission( + MakeInfo(tokenId, PID, permissionName), nullptr, CALLER_PID)); +} + +/* + * @tc.name: StopUsingPermissionMockTest001 + * @tc.desc: PermissionRecordManager::StopUsingPermission function test + * @tc.type: FUNC + * @tc.require: + */ +HWTEST_F(PermissionRecordManagerMockTest, StopUsingPermissionMockTest001, TestSize.Level0) +{ + std::string permissionName = INVALID_PERMISSION_NAME; + AccessTokenID tokenId = NATIVE_TOKEN_WITH_PERM; + + EXPECT_EQ(PrivacyError::ERR_PARAM_INVALID, PermissionRecordManager::GetInstance().StopUsingPermission( + tokenId, PID, permissionName, CALLER_PID)); + + permissionName = MICROPHONE_PERMISSION_NAME; + EXPECT_EQ(Constant::SUCCESS, PermissionRecordManager::GetInstance().StopUsingPermission( + tokenId, PID, permissionName, CALLER_PID)); + + tokenId = NATIVE_TOKEN_WITHOUT_PERM; + EXPECT_EQ(PrivacyError::ERR_PARAM_INVALID, PermissionRecordManager::GetInstance().StopUsingPermission( + tokenId, PID, permissionName, CALLER_PID)); + + permissionName = CAMERA_PERMISSION_NAME; + EXPECT_EQ(PrivacyError::ERR_PARAM_INVALID, PermissionRecordManager::GetInstance().StopUsingPermission( + tokenId, PID, permissionName, CALLER_PID)); + + tokenId = NATIVE_TOKEN_WITH_PERM; + EXPECT_EQ(Constant::SUCCESS, PermissionRecordManager::GetInstance().StopUsingPermission( + tokenId, PID, permissionName, CALLER_PID)); + + tokenId = g_shellToken; + EXPECT_EQ(PrivacyError::ERR_PARAM_INVALID, PermissionRecordManager::GetInstance().StopUsingPermission( + tokenId, PID, permissionName, CALLER_PID)); +} + +/* + * @tc.name: IsAllowedUsingPermissionMockTest001 + * @tc.desc: PermissionRecordManager::StopUsingPermission function test + * @tc.type: FUNC + * @tc.require: + */ +HWTEST_F(PermissionRecordManagerMockTest, IsAllowedUsingPermissionMockTest001, TestSize.Level0) +{ + std::string permissionName = INVALID_PERMISSION_NAME; + AccessTokenID tokenId = NATIVE_TOKEN_WITH_PERM; + + EXPECT_EQ(false, PermissionRecordManager::GetInstance().IsAllowedUsingPermission(tokenId, permissionName, PID)); + + permissionName = MICROPHONE_PERMISSION_NAME; + EXPECT_EQ(true, PermissionRecordManager::GetInstance().IsAllowedUsingPermission(tokenId, permissionName, PID)); + + tokenId = NATIVE_TOKEN_WITHOUT_PERM; + EXPECT_EQ(false, PermissionRecordManager::GetInstance().IsAllowedUsingPermission(tokenId, permissionName, PID)); + + permissionName = CAMERA_PERMISSION_NAME; + EXPECT_EQ(false, PermissionRecordManager::GetInstance().IsAllowedUsingPermission(tokenId, permissionName, PID)); + + tokenId = NATIVE_TOKEN_WITH_PERM; + EXPECT_EQ(true, PermissionRecordManager::GetInstance().IsAllowedUsingPermission(tokenId, permissionName, PID)); + + tokenId = g_shellToken; + EXPECT_EQ(false, PermissionRecordManager::GetInstance().IsAllowedUsingPermission(tokenId, permissionName, PID)); +} +} // namespace AccessToken +} // namespace Security +} // namespace OHOS \ No newline at end of file diff --git a/services/privacymanager/test/unittest/BUILD.gn b/services/privacymanager/test/unittest/BUILD.gn index c7e4cb58daef7da74b800e4b27e440d5f66bd349..6c7a7127d4fae8d1156ab708ba5d831db6f7d326 100644 --- a/services/privacymanager/test/unittest/BUILD.gn +++ b/services/privacymanager/test/unittest/BUILD.gn @@ -59,6 +59,7 @@ if (is_standard_system && ability_base_enable == true) { "../../src/active/perm_active_status_change_callback_proxy.cpp", "../../src/active/state_change_callback_proxy.cpp", "../../src/common/constant.cpp", + "../../src/common/access_token_helper.cpp", "../../src/database/data_translator.cpp", "../../src/database/permission_used_record_db.cpp", "../../src/database/privacy_field_const.cpp", diff --git a/test/fuzztest/services/privacy/privacy_service_fuzz.gni b/test/fuzztest/services/privacy/privacy_service_fuzz.gni index f833e86570a4e63666d1136821b757b948cf2307..ecdcfe533700d41be9323d0039acbd464a0ac2cf 100644 --- a/test/fuzztest/services/privacy/privacy_service_fuzz.gni +++ b/test/fuzztest/services/privacy/privacy_service_fuzz.gni @@ -74,6 +74,7 @@ privacy_sources = [ "${access_token_path}/services/privacymanager/src/active/perm_active_status_change_callback_proxy.cpp", "${access_token_path}/services/privacymanager/src/active/state_change_callback_proxy.cpp", "${access_token_path}/services/privacymanager/src/common/constant.cpp", + "${access_token_path}/services/privacymanager/src/common/access_token_helper.cpp", "${access_token_path}/services/privacymanager/src/database/data_translator.cpp", "${access_token_path}/services/privacymanager/src/database/permission_used_record_db.cpp", "${access_token_path}/services/privacymanager/src/database/privacy_field_const.cpp",