/* * Copyright (C) 2022 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 "permission_utils.h" #include #include "access_token.h" #include "accesstoken_kit.h" #include "el5_filekey_manager_kit.h" #include "ipc_skeleton.h" #include "iservice_registry.h" #include "media_file_utils.h" #include "media_log.h" #include "medialibrary_db_const.h" #include "medialibrary_errno.h" #include "medialibrary_tracer.h" #include "privacy_kit.h" #include "system_ability_definition.h" #include "tokenid_kit.h" namespace OHOS { namespace Media { using namespace std; using namespace OHOS::Security::AccessToken; using namespace OHOS::AppExecFwk::Constants; const int32_t CAPACITY = 50; bool g_isDelayTask; const int32_t HDC_SHELL_UID = 2000; const int32_t BASE_USER_RANGE = 200000; std::mutex PermissionUtils::uninstallMutex_; std::list> PermissionUtils::bundleInfoList_ = {}; std::unordered_map>::iterator> PermissionUtils::bundleInfoMap_ = {}; std::mutex addPhotoPermissionRecordLock_; std::thread delayTask_; std::vector infos_; sptr PermissionUtils::bundleMgr_ = nullptr; mutex PermissionUtils::bundleMgrMutex_; sptr PermissionUtils::GetSysBundleManager() { if (bundleMgr_ != nullptr) { return bundleMgr_; } lock_guard lock(bundleMgrMutex_); if (bundleMgr_ != nullptr) { return bundleMgr_; } auto systemAbilityMgr = SystemAbilityManagerClient::GetInstance().GetSystemAbilityManager(); if (systemAbilityMgr == nullptr) { MEDIA_ERR_LOG("Failed to get SystemAbilityManager."); return nullptr; } auto bundleObj = systemAbilityMgr->GetSystemAbility(BUNDLE_MGR_SERVICE_SYS_ABILITY_ID); if (bundleObj == nullptr) { MEDIA_ERR_LOG("Remote object is nullptr."); return nullptr; } auto bundleMgr = iface_cast(bundleObj); if (bundleMgr == nullptr) { MEDIA_ERR_LOG("Failed to iface_cast"); return nullptr; } bundleMgr_ = bundleMgr; return bundleMgr_; } void PermissionUtils::GetBundleNameFromCache(int uid, string &bundleName) { lock_guard lock(uninstallMutex_); auto iter = bundleInfoMap_.find(uid); if (iter != bundleInfoMap_.end() && !iter->second->second.bundleName.empty()) { bundleInfoList_.splice(bundleInfoList_.begin(), bundleInfoList_, iter->second); bundleName = iter->second->second.bundleName; return; } bundleMgr_ = GetSysBundleManager(); if (bundleMgr_ == nullptr) { bundleName = ""; return; } auto result = bundleMgr_->GetBundleNameForUid(uid, bundleName); if (!result) { bundleName = ""; return; } UpdateBundleNameInCache(uid, bundleName); } void PermissionUtils::GetPackageNameFromCache(int uid, const string &bundleName, string &packageName) { lock_guard lock(uninstallMutex_); auto iter = bundleInfoMap_.find(uid); if (iter != bundleInfoMap_.end() && !iter->second->second.packageName.empty()) { bundleInfoList_.splice(bundleInfoList_.begin(), bundleInfoList_, iter->second); packageName = iter->second->second.packageName; return; } int32_t userId = uid / BASE_USER_RANGE; MEDIA_DEBUG_LOG("uid:%{private}d, userId:%{private}d", uid, userId); AAFwk::Want want; auto bundleMgr = GetSysBundleManager(); if (bundleMgr == nullptr) { MEDIA_ERR_LOG("Get BundleManager failed"); packageName = ""; return; } int ret = bundleMgr->GetLaunchWantForBundle(bundleName, want, userId); if (ret != ERR_OK) { MEDIA_ERR_LOG("Can not get bundleName by want, err=%{public}d, userId=%{private}d", ret, userId); packageName = ""; return; } string abilityName = want.GetOperation().GetAbilityName(); packageName = bundleMgr->GetAbilityLabel(bundleName, abilityName); UpdatePackageNameInCache(uid, packageName); } void PermissionUtils::GetAppIdFromCache(int uid, const string &bundleName, string &appId) { lock_guard lock(uninstallMutex_); auto iter = bundleInfoMap_.find(uid); if (iter != bundleInfoMap_.end() && !iter->second->second.appId.empty()) { bundleInfoList_.splice(bundleInfoList_.begin(), bundleInfoList_, iter->second); appId = iter->second->second.appId; return; } int32_t userId = uid / BASE_USER_RANGE; MEDIA_DEBUG_LOG("uid:%{private}d, userId:%{private}d", uid, userId); auto bundleMgr_ = GetSysBundleManager(); if (bundleMgr_ == nullptr) { MEDIA_ERR_LOG("Get BundleManager failed"); return; } appId = bundleMgr_->GetAppIdByBundleName(bundleName, userId); UpdateAppIdInCache(uid, appId); } void PermissionUtils::UpdateLatestBundleInfo(int uid, const BundleInfo &bundleInfo) { auto iter = bundleInfoMap_.find(uid); if (iter != bundleInfoMap_.end()) { bundleInfoList_.erase(iter->second); } bundleInfoList_.push_front(make_pair(uid, bundleInfo)); bundleInfoMap_[uid] = bundleInfoList_.begin(); if (bundleInfoMap_.size() > CAPACITY) { int32_t deleteKey = bundleInfoList_.back().first; bundleInfoMap_.erase(deleteKey); bundleInfoList_.pop_back(); } } void PermissionUtils::UpdateBundleNameInCache(int uid, const string &bundleName) { auto iter = bundleInfoMap_.find(uid); if (iter != bundleInfoMap_.end()) { BundleInfo bundleInfo = bundleInfoMap_[uid]->second; bundleInfo.bundleName = bundleName; UpdateLatestBundleInfo(uid, bundleInfo); return; } BundleInfo bundleInfo { bundleName, "", "" }; UpdateLatestBundleInfo(uid, bundleInfo); } void PermissionUtils::UpdatePackageNameInCache(int uid, const string &packageName) { auto iter = bundleInfoMap_.find(uid); if (iter != bundleInfoMap_.end()) { BundleInfo bundleInfo = bundleInfoMap_[uid]->second; bundleInfo.packageName = packageName; UpdateLatestBundleInfo(uid, bundleInfo); return; } BundleInfo bundleInfo { "", packageName, "" }; UpdateLatestBundleInfo(uid, bundleInfo); } void PermissionUtils::UpdateAppIdInCache(int uid, const string &appId) { BundleInfo bundleInfo { "", "", appId }; auto iter = bundleInfoMap_.find(uid); if (iter != bundleInfoMap_.end()) { bundleInfo = bundleInfoMap_[uid]->second; bundleInfo.appId = appId; } UpdateLatestBundleInfo(uid, bundleInfo); } void PermissionUtils::ClearBundleInfoInCache() { lock_guard lock(uninstallMutex_); bundleInfoMap_.clear(); bundleInfoList_.clear(); MEDIA_INFO_LOG("clear all info from cache"); } void PermissionUtils::GetClientBundle(const int uid, string &bundleName) { GetBundleNameFromCache(uid, bundleName); } void PermissionUtils::GetPackageName(const int uid, std::string &packageName) { packageName = ""; string bundleName; GetClientBundle(uid, bundleName); if (bundleName.empty()) { MEDIA_ERR_LOG("Get bundle name failed"); return; } GetPackageNameFromCache(uid, bundleName, packageName); } bool inline ShouldAddPermissionRecord(const AccessTokenID &token) { return (AccessTokenKit::GetTokenTypeFlag(token) == TOKEN_HAP); } void AddPermissionRecord(const AccessTokenID &token, const string &perm, const bool permGranted) { if (!ShouldAddPermissionRecord(token)) { return; } int res = PrivacyKit::AddPermissionUsedRecord(token, perm, !!permGranted, !permGranted, true); if (res != 0) { /* Failed to add permission used record, not fatal */ MEDIA_WARN_LOG("Failed to add permission used record: %{public}s, permGranted: %{public}d, err: %{public}d", perm.c_str(), permGranted, res); } } vector GetPermissionRecord() { lock_guard lock(addPhotoPermissionRecordLock_); vector result = infos_; infos_.clear(); return result; } void AddPermissionRecord() { vector infos = GetPermissionRecord(); for (const auto &info : infos) { int32_t ret = PrivacyKit::AddPermissionUsedRecord(info, true); if (ret != 0) { /* Failed to add permission used record, not fatal */ MEDIA_WARN_LOG("Failed to add permission used record: %{public}s, permGranted: %{public}d, err: %{public}d", info.permissionName.c_str(), info.successCount, ret); } MEDIA_DEBUG_LOG("Info: token = %{private}d, perm = %{private}s, permGranted = %{private}d, \ !permGranted = %{private}d, type = %{public}d", info.tokenId, info.permissionName.c_str(), info.successCount, info.failCount, info.type); } infos.clear(); } void DelayAddPermissionRecord() { string name("DelayAddPermissionRecord"); pthread_setname_np(pthread_self(), name.c_str()); MEDIA_INFO_LOG("DelayTask start"); std::this_thread::sleep_for(std::chrono::seconds(1)); AddPermissionRecord(); g_isDelayTask = false; MEDIA_INFO_LOG("DelayTask end"); } void DelayTaskInit() { if (!g_isDelayTask) { MEDIA_INFO_LOG("DelayTaskInit"); delayTask_ = thread(DelayAddPermissionRecord); delayTask_.detach(); g_isDelayTask = true; } } void CollectPermissionRecord(const AccessTokenID &token, const string &perm, const bool permGranted, const PermissionUsedType type) { lock_guard lock(addPhotoPermissionRecordLock_); DelayTaskInit(); if (!ShouldAddPermissionRecord(token)) { return; } AddPermParamInfo info = {token, perm, permGranted, !permGranted, type}; auto iter = find_if(infos_.begin(), infos_.end(), [&token, &perm, type](auto &info) { return info.tokenId == token && info.permissionName == perm && info.type == type; }); if (iter == infos_.end()) { infos_.push_back(info); } else if (permGranted) { iter->successCount += 1; } else if (!permGranted) { iter->failCount += 1; } } void PermissionUtils::CollectPermissionInfo(const string &permission, const bool permGranted, const PermissionUsedType type) { AccessTokenID tokenCaller = IPCSkeleton::GetCallingTokenID(); CollectPermissionRecord(tokenCaller, permission, permGranted, type); } bool PermissionUtils::CheckPhotoCallerPermission(const string &permission) { PermissionUsedType type = PermissionUsedTypeValue::NORMAL_TYPE; AccessTokenID tokenCaller = IPCSkeleton::GetCallingTokenID(); int res = AccessTokenKit::VerifyAccessToken(tokenCaller, permission); if (res != PermissionState::PERMISSION_GRANTED) { MEDIA_ERR_LOG("Have no media permission: %{public}s", permission.c_str()); CollectPermissionRecord(tokenCaller, permission, false, type); return false; } CollectPermissionRecord(tokenCaller, permission, true, type); return true; } bool PermissionUtils::CheckPhotoCallerPermission(const vector &perms) { if (perms.empty()) { return false; } for (const auto &perm : perms) { if (!CheckPhotoCallerPermission(perm)) { return false; } } return true; } bool PermissionUtils::CheckCallerPermission(const string &permission) { MediaLibraryTracer tracer; tracer.Start("CheckCallerPermission"); AccessTokenID tokenCaller = IPCSkeleton::GetCallingTokenID(); int res = AccessTokenKit::VerifyAccessToken(tokenCaller, permission); if (res != PermissionState::PERMISSION_GRANTED) { MEDIA_ERR_LOG("Have no media permission: %{public}s", permission.c_str()); AddPermissionRecord(tokenCaller, permission, false); return false; } AddPermissionRecord(tokenCaller, permission, true); return true; } /* Check whether caller has at least one of @perms */ bool PermissionUtils::CheckHasPermission(const vector &perms) { if (perms.empty()) { return false; } for (const auto &perm : perms) { if (CheckCallerPermission(perm)) { return true; } } return false; } /* Check whether caller has all the @perms */ bool PermissionUtils::CheckCallerPermission(const vector &perms) { if (perms.empty()) { return false; } for (const auto &perm : perms) { if (!CheckCallerPermission(perm)) { return false; } } return true; } uint32_t PermissionUtils::GetTokenId() { return IPCSkeleton::GetCallingTokenID(); } bool PermissionUtils::IsSystemApp() { uint64_t tokenId = IPCSkeleton::GetCallingFullTokenID(); return TokenIdKit::IsSystemAppByFullTokenID(tokenId); } bool PermissionUtils::CheckIsSystemAppByUid() { int uid = IPCSkeleton::GetCallingUid(); bundleMgr_ = GetSysBundleManager(); if (bundleMgr_ == nullptr) { MEDIA_ERR_LOG("Can not get bundleMgr"); return false; } return bundleMgr_->CheckIsSystemAppByUid(uid); } bool PermissionUtils::IsNativeSAApp() { uint32_t tokenId = IPCSkeleton::GetCallingTokenID(); ATokenTypeEnum tokenType = AccessTokenKit::GetTokenTypeFlag(tokenId); MEDIA_DEBUG_LOG("check if native sa token, tokenId:%{public}d, tokenType:%{public}d", tokenId, tokenType); if (tokenType == ATokenTypeEnum::TOKEN_NATIVE) { return true; } return false; } bool PermissionUtils::IsRootShell() { return IPCSkeleton::GetCallingUid() == 0; } bool PermissionUtils::IsHdcShell() { return IPCSkeleton::GetCallingUid() == HDC_SHELL_UID; } string PermissionUtils::GetPackageNameByBundleName(const string &bundleName) { const static int32_t INVALID_UID = -1; string packageName = ""; int uid = IPCSkeleton::GetCallingUid(); if (uid <= INVALID_UID) { MEDIA_ERR_LOG("Get INVALID_UID UID %{public}d", uid); return packageName; } GetPackageNameFromCache(uid, bundleName, packageName); return packageName; } string PermissionUtils::GetAppIdByBundleName(const string &bundleName) { int uid = IPCSkeleton::GetCallingUid(); return GetAppIdByBundleName(bundleName, uid); } string PermissionUtils::GetAppIdByBundleName(const string &bundleName, int32_t uid) { if (uid <= INVALID_UID) { MEDIA_ERR_LOG("Get INVALID_UID UID %{public}d", uid); return ""; } string appId = ""; GetAppIdFromCache(uid, bundleName, appId); return appId; } bool PermissionUtils::SetEPolicy() { MEDIA_INFO_LOG("SetEPolicy for directory"); int ret = Security::AccessToken::El5FilekeyManagerKit::SetFilePathPolicy(); if (ret != 0) { MEDIA_ERR_LOG("SetEPolicy fail of %{public}d", ret); return false; } return true; } } // namespace Media } // namespace OHOS