* Copyright (c) 2023-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 "bms_wrapper.h"
#include <cstring>
#include "securec.h"
#include "accesstoken_kit.h"
#include "app_provision_info.h"
#include "bundle_mgr_client.h"
#include "bundle_mgr_interface.h"
#include "hap_token_info.h"
#include "ipc_skeleton.h"
#include "iservice_registry.h"
#include "asset_type.h"
#include "asset_log.h"
#include "system_event_wrapper.h"
using namespace OHOS;
using namespace AppExecFwk;
using namespace Security::AccessToken;
namespace {
constexpr int BUNDLE_MGR_SERVICE_SYS_ABILITY_ID = 401;
const char * const UPGRADE_HAP_LIST[] = ASSET_UPGRADE_HAP_CONFIG;
const char * const CE_UPGRADE_CONFIG = ASSET_CE_UPGRADE_CONFIG;
bool AssetMemCmp(const void *ptr1, const void *ptr2, uint32_t size1, uint32_t size2)
{
if (size1 != size2) {
return false;
}
return memcmp(ptr1, ptr2, size1) == EOK;
}
sptr<IBundleMgr> GetBundleMgr()
{
auto systemAbilityManager = SystemAbilityManagerClient::GetInstance().GetSystemAbilityManager();
if (systemAbilityManager == nullptr) {
LOGE("[FATAL]systemAbilityManager is nullptr, please check.");
return nullptr;
}
auto bundleMgrRemoteObj = systemAbilityManager->GetSystemAbility(BUNDLE_MGR_SERVICE_SYS_ABILITY_ID);
if (bundleMgrRemoteObj == nullptr) {
LOGE("[FATAL]bundleMgrRemoteObj is nullptr, please check.");
return nullptr;
}
return iface_cast<IBundleMgr>(bundleMgrRemoteObj);
}
int32_t GetBundleNameAndAppIndex(AssetGroupInfo &assetGroupInfo, ProcessInfo *processInfo)
{
processInfo->hapInfo.appIndex = assetGroupInfo.appIndex;
if (memcpy_s(processInfo->processName.data, processInfo->processName.size,
assetGroupInfo.bundleName.c_str(), assetGroupInfo.bundleName.size()) != EOK) {
LOGE("[FATAL]The processName buffer is too small. Expect size: %{public}zu, actual size: %{public}u",
assetGroupInfo.bundleName.size(), processInfo->processName.size);
return ASSET_OUT_OF_MEMORY;
}
processInfo->processName.size = assetGroupInfo.bundleName.size();
return ASSET_SUCCESS;
}
int32_t GetBundleInfo(AssetGroupInfo &assetGroupInfo, ProcessInfo *processInfo)
{
if (memcpy_s(processInfo->hapInfo.appId.data, processInfo->hapInfo.appId.size, assetGroupInfo.appId.c_str(),
assetGroupInfo.appId.size()) != EOK) {
LOGE("[FATAL]The app id buffer is too small. Expect size: %{public}zu, actual size: %{public}u",
assetGroupInfo.appId.size(), processInfo->hapInfo.appId.size);
return ASSET_OUT_OF_MEMORY;
}
processInfo->hapInfo.appId.size = assetGroupInfo.appId.size();
if (processInfo->hapInfo.groupId.data == nullptr || processInfo->hapInfo.groupId.size == 0) {
return ASSET_SUCCESS;
}
for (const std::string &groupId : assetGroupInfo.assetAccessGroups) {
if (groupId.size() == processInfo->hapInfo.groupId.size &&
memcmp(processInfo->hapInfo.groupId.data, groupId.data(), processInfo->hapInfo.groupId.size) == 0) {
LOGI("Found matching group id.");
return ASSET_SUCCESS;
}
}
LOGE("[FATAL]No matching group id found!");
return ASSET_INVALID_ARGUMENT;
}
int32_t GetAppProvisionInfo(AssetGroupInfo &assetGroupInfo, ProcessInfo *processInfo)
{
if (processInfo->hapInfo.developerId.data == nullptr || processInfo->hapInfo.developerId.size == 0) {
return ASSET_SUCCESS;
}
std::string mainDeveloperId;
size_t pos = assetGroupInfo.developerId.find('.');
if (pos != std::string::npos) {
mainDeveloperId = assetGroupInfo.developerId.substr(pos + 1);
} else {
mainDeveloperId = assetGroupInfo.developerId;
}
if (memcpy_s(processInfo->hapInfo.developerId.data, processInfo->hapInfo.developerId.size, mainDeveloperId.c_str(),
mainDeveloperId.size()) != EOK) {
LOGE("[FATAL]The developer id buffer is too small. Expect size: %{public}zu, actual size: %{public}u",
mainDeveloperId.size(), processInfo->hapInfo.developerId.size);
return ASSET_OUT_OF_MEMORY;
}
processInfo->hapInfo.developerId.size = mainDeveloperId.size();
return ASSET_SUCCESS;
}
int32_t GetHapProcessInfo(uint32_t userId, uint64_t uid, ProcessInfo *processInfo)
{
auto bundleMgr = GetBundleMgr();
if (bundleMgr == nullptr) {
LOGE("[FATAL]bundleMgr is nullptr, please check.");
return ASSET_BMS_ERROR;
}
AppExecFwk::BundleMgrClient bmsClient;
AssetGroupInfo assetGroupInfo;
int32_t ret = bundleMgr->GetAssetGroupsInfo(uid, assetGroupInfo);
if (ret != ASSET_SUCCESS) {
LOGE("[FATAL]GetAssetGroupsInfo failed.");
return ret;
}
ret = GetBundleNameAndAppIndex(assetGroupInfo, processInfo);
if (ret != ASSET_SUCCESS) {
return ret;
}
ret = GetBundleInfo(assetGroupInfo, processInfo);
if (ret != ASSET_SUCCESS) {
return ret;
}
return GetAppProvisionInfo(assetGroupInfo, processInfo);
}
int32_t GetNativeProcessInfo(uint32_t tokenId, uint64_t uid, ProcessInfo *processInfo)
{
NativeTokenInfo nativeTokenInfo;
int32_t ret = AccessTokenKit::GetNativeTokenInfo(tokenId, nativeTokenInfo);
if (ret != RET_SUCCESS) {
LOGE("[FATAL]Get native token info failed, ret = %{public}d", ret);
return ASSET_ACCESS_TOKEN_ERROR;
}
if (memcpy_s(processInfo->processName.data, processInfo->processName.size, nativeTokenInfo.processName.c_str(),
nativeTokenInfo.processName.size()) != EOK) {
LOGE("[FATAL]The processName buffer is too small. Expect size: %{public}zu, actual size: %{public}u",
nativeTokenInfo.processName.size(), processInfo->processName.size);
return ASSET_OUT_OF_MEMORY;
}
processInfo->processName.size = nativeTokenInfo.processName.size();
processInfo->nativeInfo.uid = uid;
return ASSET_SUCCESS;
}
void MarkGroupAsModified(const std::string &groupId, MutAssetBlobArray *groupIds)
{
if (groupIds == nullptr || groupIds->blob == nullptr || groupIds->size == 0) {
return;
}
for (uint32_t i = 0; i < groupIds->size; i++) {
if (strcmp(groupId.c_str(), groupIds->blob[i].blob) == 0) {
groupIds->blob[i].modify = true;
break;
}
}
}
void ProcessBundleInfos(const std::vector<AppExecFwk::BundleInfo> &bundleInfos,
int32_t userId, MutAssetBlobArray *groupIds)
{
std::unordered_set<std::string> targetGroupIds;
for (uint32_t i = 0; i < groupIds->size; i++) {
targetGroupIds.insert(groupIds->blob[i].blob);
}
for (const AppExecFwk::BundleInfo &bundleInfo : bundleInfos) {
for (const std::string &groupId : bundleInfo.applicationInfo.assetAccessGroups) {
if (targetGroupIds.find(groupId) != targetGroupIds.end()) {
LOGI("Found matching group id. Do not remove data in this group");
MarkGroupAsModified(groupId, groupIds);
}
}
}
}
int32_t ProcessGroupIds(AssetGroupInfo &assetGroupInfo, MutAssetBlobArrayChangeable *groupIds)
{
size_t i = 0;
for (const std::string &groupId : assetGroupInfo.assetAccessGroups) {
if (memcpy_s(groupIds->blob[i].data, groupIds->blob[i].size,
groupId.c_str(), groupId.size()) != EOK) {
LOGE("[FATAL]The grooupId buffer is too small. Expect size: %{public}zu, actual size: %{public}u",
groupId.size(), groupIds->blob[i].size);
return ASSET_OUT_OF_MEMORY;
}
groupIds->blob[i].size = groupId.size();
i++;
}
groupIds->size = i;
return ASSET_SUCCESS;
}
int32_t ProcessDeveloperId(AssetGroupInfo &assetGroupInfo, Asset_Blob *developerId)
{
if (developerId->data == nullptr || developerId->size == 0) {
return ASSET_BMS_ERROR;
}
std::string mainDeveloperId;
size_t pos = assetGroupInfo.developerId.find('.');
if (pos != std::string::npos) {
mainDeveloperId = assetGroupInfo.developerId.substr(pos + 1);
} else {
mainDeveloperId = assetGroupInfo.developerId;
}
if (memcpy_s(developerId->data, developerId->size, mainDeveloperId.c_str(),
mainDeveloperId.size()) != EOK) {
LOGE("[FATAL]The developer id buffer is too small. Expect size: %{public}zu, actual size: %{public}u",
mainDeveloperId.size(), developerId->size);
return ASSET_OUT_OF_MEMORY;
}
developerId->size = mainDeveloperId.size();
return ASSET_SUCCESS;
}
}
int32_t GetCallingProcessInfo(uint32_t userId, uint64_t uid, ProcessInfo *processInfo, bool preload)
{
if (processInfo == nullptr) {
return ASSET_INVALID_ARGUMENT;
}
processInfo->userId = userId;
auto tokenId = IPCSkeleton::GetCallingTokenID();
ATokenTypeEnum tokenType = ATokenTypeEnum::TOKEN_HAP;
if (!preload) {
tokenType = AccessTokenKit::GetTokenTypeFlag(tokenId);
}
int32_t res = ASSET_SUCCESS;
switch (tokenType) {
case ATokenTypeEnum::TOKEN_HAP:
if (processInfo->hapInfo.groupId.data != nullptr) {
processInfo->ownerType = HAP_GROUP;
} else {
processInfo->ownerType = HAP;
}
res = GetHapProcessInfo(userId, uid, processInfo);
break;
case ATokenTypeEnum::TOKEN_NATIVE:
case ATokenTypeEnum::TOKEN_SHELL:
processInfo->ownerType = NATIVE;
res = GetNativeProcessInfo(tokenId, uid, processInfo);
break;
default:
LOGE("[FATAL]Invalid calling type: %{public}d", tokenType);
res = ASSET_INVALID_ARGUMENT;
}
return res;
}
int32_t GetCloneAppIndexes(int32_t userId, int32_t *appIndexes, uint32_t *indexSize, const char *appName)
{
auto bundleMgr = GetBundleMgr();
if (bundleMgr == nullptr) {
LOGE("[FATAL]bundleMgr is nullptr, please check.");
return ASSET_BMS_ERROR;
}
std::vector<int32_t> indexes;
int32_t ret = bundleMgr->GetCloneAppIndexes(appName, indexes, userId);
if (ret != ASSET_SUCCESS) {
LOGE("Get clone app indexes failed.");
return ASSET_BMS_ERROR;
}
if (*indexSize < indexes.size()) {
LOGE("Too short index size.");
return ASSET_INVALID_ARGUMENT;
}
for (size_t i = 0; i < indexes.size(); i++) {
*(appIndexes + i) = indexes[i];
}
*indexSize = indexes.size();
return ASSET_SUCCESS;
}
int32_t IsHapInAllowList(int32_t userId, const char *appName, bool *is_in_list)
{
if (appName == nullptr) {
LOGE("[FATAL]App name is null.");
return ASSET_INVALID_ARGUMENT;
}
AppExecFwk::BundleInfo bundleInfo;
AppExecFwk::BundleMgrClient bmsClient;
if (!bmsClient.GetBundleInfo(appName, BundleFlag::GET_BUNDLE_WITH_HASH_VALUE, bundleInfo, userId)) {
LOGE("[FATAL]Get bundle info failed!");
return ASSET_BMS_ERROR;
}
for (uint32_t i = 0; i < ARRAY_SIZE(UPGRADE_HAP_LIST); ++i) {
if (AssetMemCmp(UPGRADE_HAP_LIST[i],
bundleInfo.appId.c_str(),
strlen(UPGRADE_HAP_LIST[i]),
bundleInfo.appId.size())) {
*is_in_list = true;
return ASSET_SUCCESS;
}
}
*is_in_list = false;
return ASSET_SUCCESS;
}
int32_t GetUninstallGroups(int32_t userId, ConstAssetBlob *developerId, MutAssetBlobArray *groupIds)
{
if (developerId == nullptr || groupIds == nullptr) {
return ASSET_BMS_ERROR;
}
auto bundleMgr = GetBundleMgr();
if (bundleMgr == nullptr) {
LOGE("[FATAL]bundleMgr is nullptr, please check.");
return ASSET_BMS_ERROR;
}
std::string useDeveloperId(reinterpret_cast<const char*>(developerId->data), developerId->size);
std::vector<AppExecFwk::BundleInfo> bundleInfos;
int32_t ret = bundleMgr->GetAllBundleInfoByDeveloperId(useDeveloperId, bundleInfos, userId);
if (ret != RET_SUCCESS && ret != ERR_BUNDLE_MANAGER_INVALID_DEVELOPERID) {
LOGE("[FATAL]GetAllBundleInfoByDeveloperId failed. ret:%{public}d", ret);
return ASSET_BMS_ERROR;
}
ProcessBundleInfos(bundleInfos, userId, groupIds);
return ASSET_SUCCESS;
}
const char *GetCeUpgradeInfo()
{
return CE_UPGRADE_CONFIG;
}
int32_t GetCallingHapGroups(uint64_t uid, MutAssetBlobArrayChangeable *groupIds, Asset_Blob *developerId)
{
auto bundleMgr = GetBundleMgr();
if (bundleMgr == nullptr) {
LOGE("[FATAL]bundleMgr is nullptr, please check.");
return ASSET_BMS_ERROR;
}
AppExecFwk::BundleMgrClient bmsClient;
AssetGroupInfo assetGroupInfo;
int32_t ret = bundleMgr->GetAssetGroupsInfo(uid, assetGroupInfo);
if (ret != ASSET_SUCCESS) {
LOGE("[FATAL]GetAssetGroupsInfo failed. ret: %{public}d", ret);
return ASSET_BMS_ERROR;
}
ret = ProcessGroupIds(assetGroupInfo, groupIds);
if (ret != ASSET_SUCCESS) {
LOGE("[FATAL]ProcessGroupIds failed. ret: %{public}d", ret);
return ret;
}
return ProcessDeveloperId(assetGroupInfo, developerId);
}