• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2021 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #include "distributed_sched_permission.h"
17 
18 #include "accesstoken_kit.h"
19 #include "adapter/dnetwork_adapter.h"
20 #include "bundle/bundle_manager_internal.h"
21 #include "caller_info.h"
22 #include "datetime_ex.h"
23 #include "device_auth_defines.h"
24 #include "distributed_sched_adapter.h"
25 #include "dtbschedmgr_log.h"
26 #include "ipc_skeleton.h"
27 
28 namespace OHOS {
29 namespace DistributedSchedule {
30 using namespace OHOS::Security;
31 using namespace AAFwk;
32 namespace {
33 const std::string TAG = "DistributedSchedPermission";
34 const std::string FOUNDATION_PROCESS_NAME = "foundation";
35 const std::string DMS_API_VERSION = "dmsApiVersion";
36 const std::string DMS_IS_CALLER_BACKGROUND = "dmsIsCallerBackGround";
37 const std::string DMS_MISSION_ID = "dmsMissionId";
38 const std::string DMS_VERSION_ID = "dmsVersion";
39 const std::string PERMISSION_START_ABILIIES_FROM_BACKGROUND = "ohos.permission.START_ABILIIES_FROM_BACKGROUND";
40 const std::string PERMISSION_START_ABILITIES_FROM_BACKGROUND = "ohos.permission.START_ABILITIES_FROM_BACKGROUND";
41 const std::string PERMISSION_START_INVISIBLE_ABILITY = "ohos.permission.START_INVISIBLE_ABILITY";
42 constexpr int32_t DEFAULT_DMS_API_VERSION = 9;
43 const int DEFAULT_DMS_MISSION_ID = -1;
44 const int FA_MODULE_ALLOW_MIN_API_VERSION = 8;
45 }
46 IMPLEMENT_SINGLE_INSTANCE(DistributedSchedPermission);
from_json(const nlohmann::json & jsonObject,GroupInfo & groupInfo)47 void from_json(const nlohmann::json& jsonObject, GroupInfo& groupInfo)
48 {
49     if (jsonObject.find(FIELD_GROUP_NAME) != jsonObject.end()) {
50         jsonObject.at(FIELD_GROUP_NAME).get_to(groupInfo.groupName);
51     }
52     if (jsonObject.find(FIELD_GROUP_ID) != jsonObject.end()) {
53         jsonObject.at(FIELD_GROUP_ID).get_to(groupInfo.groupId);
54     }
55     if (jsonObject.find(FIELD_GROUP_OWNER) != jsonObject.end()) {
56         jsonObject.at(FIELD_GROUP_OWNER).get_to(groupInfo.groupOwner);
57     }
58     if (jsonObject.find(FIELD_GROUP_TYPE) != jsonObject.end()) {
59         jsonObject.at(FIELD_GROUP_TYPE).get_to(groupInfo.groupType);
60     }
61     if (jsonObject.find(FIELD_GROUP_VISIBILITY) != jsonObject.end()) {
62         jsonObject.at(FIELD_GROUP_VISIBILITY).get_to(groupInfo.groupVisibility);
63     }
64 }
65 
CheckSendResultPermission(const AAFwk::Want & want,const CallerInfo & callerInfo,const AccountInfo & accountInfo,AppExecFwk::AbilityInfo & targetAbility)66 int32_t DistributedSchedPermission::CheckSendResultPermission(const AAFwk::Want& want, const CallerInfo& callerInfo,
67     const AccountInfo& accountInfo, AppExecFwk::AbilityInfo& targetAbility)
68 {
69     // 1.check account access permission in no account networking environment.
70     if (!CheckAccountAccessPermission(callerInfo, accountInfo, targetAbility.bundleName)) {
71         HILOGE("CheckAccountAccessPermission denied or failed!");
72         return DMS_ACCOUNT_ACCESS_PERMISSION_DENIED;
73     }
74     // 2.check component access permission, when the ability is not visible.
75     if (!CheckComponentAccessPermission(targetAbility, callerInfo, accountInfo, want)) {
76         HILOGE("CheckComponentAccessPermission denied or failed! the callee component do not have permission");
77         return DMS_COMPONENT_ACCESS_PERMISSION_DENIED;
78     }
79     // 3.check application custom permissions
80     if (!CheckCustomPermission(targetAbility, callerInfo)) {
81         HILOGE("CheckCustomPermission denied or failed! the caller component do not have permission");
82         return DMS_COMPONENT_ACCESS_PERMISSION_DENIED;
83     }
84     HILOGI("CheckSendResultPermission success!!");
85     return ERR_OK;
86 }
87 
CheckStartPermission(const AAFwk::Want & want,const CallerInfo & callerInfo,const AccountInfo & accountInfo,AppExecFwk::AbilityInfo & targetAbility)88 int32_t DistributedSchedPermission::CheckStartPermission(const AAFwk::Want& want, const CallerInfo& callerInfo,
89     const AccountInfo& accountInfo, AppExecFwk::AbilityInfo& targetAbility)
90 {
91     // 1.check account access permission in no account networking environment.
92     if (!CheckAccountAccessPermission(callerInfo, accountInfo, targetAbility.bundleName)) {
93         HILOGE("CheckAccountAccessPermission denied or failed!");
94         return DMS_ACCOUNT_ACCESS_PERMISSION_DENIED;
95     }
96     // 2.check start control permissions.
97     if (!CheckStartControlPermission(targetAbility, callerInfo, want)) {
98         HILOGE("CheckStartControlPermission denied or failed! the callee component do not have permission");
99         return DMS_START_CONTROL_PERMISSION_DENIED;
100     }
101     // 3.check application custom permissions
102     if (!CheckCustomPermission(targetAbility, callerInfo)) {
103         HILOGE("CheckCustomPermission denied or failed! the caller component do not have permission");
104         return DMS_COMPONENT_ACCESS_PERMISSION_DENIED;
105     }
106     HILOGI("CheckDistributedPermission success!!");
107     return ERR_OK;
108 }
109 
GetAccountInfo(const std::string & remoteNetworkId,const CallerInfo & callerInfo,AccountInfo & accountInfo)110 int32_t DistributedSchedPermission::GetAccountInfo(const std::string& remoteNetworkId,
111     const CallerInfo& callerInfo, AccountInfo& accountInfo)
112 {
113     if (remoteNetworkId.empty()) {
114         HILOGE("remoteNetworkId is empty");
115         return ERR_NULL_OBJECT;
116     }
117     std::string udid = DnetworkAdapter::GetInstance()->GetUdidByNetworkId(remoteNetworkId);
118     if (udid.empty()) {
119         HILOGE("udid is empty");
120         return ERR_NULL_OBJECT;
121     }
122     if (!GetRelatedGroups(udid, callerInfo.bundleNames, accountInfo)) {
123         HILOGE("GetRelatedGroups failed");
124         return INVALID_PARAMETERS_ERR;
125     }
126     return ERR_OK;
127 }
128 
GetRelatedGroups(const std::string & udid,const std::vector<std::string> & bundleNames,AccountInfo & accountInfo)129 bool DistributedSchedPermission::GetRelatedGroups(const std::string& udid,
130     const std::vector<std::string>& bundleNames, AccountInfo& accountInfo)
131 {
132     for (const auto& bundleName : bundleNames) {
133         std::string returnGroups;
134         if (!DistributedSchedAdapter::GetInstance().GetRelatedGroups(udid, bundleName, returnGroups)) {
135             continue;
136         }
137         std::vector<GroupInfo> groupInfos;
138         if (!ParseGroupInfos(returnGroups, groupInfos)) {
139             continue;
140         }
141         for (const auto& groupInfo : groupInfos) {
142             // check group type is whether (same count or point to point) or not
143             if (groupInfo.groupType != GroupType::IDENTICAL_ACCOUNT_GROUP
144                 && groupInfo.groupType != GroupType::PEER_TO_PEER_GROUP) {
145                 continue;
146             }
147             accountInfo.groupIdList.push_back(groupInfo.groupId);
148             if (groupInfo.groupType == GroupType::IDENTICAL_ACCOUNT_GROUP
149                 && accountInfo.accountType != IDistributedSched::SAME_ACCOUNT_TYPE) {
150                 accountInfo.accountType = IDistributedSched::SAME_ACCOUNT_TYPE;
151             }
152         }
153     }
154     if (accountInfo.groupIdList.empty()) {
155         HILOGE("groupIdList is empty");
156         return false;
157     }
158     return true;
159 }
160 
ParseGroupInfos(const std::string & returnGroupStr,std::vector<GroupInfo> & groupInfos)161 bool DistributedSchedPermission::ParseGroupInfos(const std::string& returnGroupStr, std::vector<GroupInfo>& groupInfos)
162 {
163     nlohmann::json groupInfoJson = nlohmann::json::parse(returnGroupStr, nullptr, false);
164     if (groupInfoJson.is_discarded()) {
165         HILOGE("returnGroupStr parse failed");
166         return false;
167     }
168     HILOGD("groupInfoJson:%{public}s", groupInfoJson.dump().c_str());
169     groupInfos = groupInfoJson.get<std::vector<GroupInfo>>();
170     if (groupInfos.empty()) {
171         HILOGE("groupInfos is empty");
172         return false;
173     }
174     return true;
175 }
176 
GetTargetAbility(const AAFwk::Want & want,AppExecFwk::AbilityInfo & targetAbility,bool needQueryExtension) const177 bool DistributedSchedPermission::GetTargetAbility(const AAFwk::Want& want,
178     AppExecFwk::AbilityInfo& targetAbility, bool needQueryExtension) const
179 {
180     if (BundleManagerInternal::QueryAbilityInfo(want, targetAbility)) {
181         if (want.GetIntParam(DMS_MISSION_ID, DEFAULT_DMS_MISSION_ID) != DEFAULT_DMS_MISSION_ID &&
182             (targetAbility.type == AppExecFwk::AbilityType::SERVICE ||
183             targetAbility.type == AppExecFwk::AbilityType::EXTENSION)) {
184             HILOGE("StartAbilityForResult can not start service and extension ability");
185             return false;
186         }
187         return true;
188     }
189     if (needQueryExtension) {
190         HILOGI("QueryAbilityInfo failed, try to QueryExtensionAbilityInfo");
191         // try to find extension
192         AppExecFwk::ExtensionAbilityInfo extensionAbility;
193         if (BundleManagerInternal::QueryExtensionAbilityInfo(want, extensionAbility)) {
194             // extensionAbilityInfo translates to abilityInfo
195             BundleManagerInternal::InitAbilityInfoFromExtension(extensionAbility, targetAbility);
196             return true;
197         }
198     }
199     HILOGE("QueryAbilityInfo failed, want bundle name=%{public}s, ability name=%{public}s.",
200         want.GetElement().GetBundleName().c_str(), want.GetElement().GetAbilityName().c_str());
201     return false;
202 }
203 
CheckGetCallerPermission(const AAFwk::Want & want,const CallerInfo & callerInfo,const AccountInfo & accountInfo,AppExecFwk::AbilityInfo & targetAbility)204 int32_t DistributedSchedPermission::CheckGetCallerPermission(const AAFwk::Want& want, const CallerInfo& callerInfo,
205     const AccountInfo& accountInfo, AppExecFwk::AbilityInfo& targetAbility)
206 {
207     // 1.check account access permission in no account networking environment.
208     if (!CheckAccountAccessPermission(callerInfo, accountInfo, targetAbility.bundleName)) {
209         HILOGE("CheckAccountAccessPermission denied or failed!");
210         return DMS_ACCOUNT_ACCESS_PERMISSION_DENIED;
211     }
212     // 2. check call with same appid
213     if (!BundleManagerInternal::IsSameAppId(callerInfo.callerAppId, targetAbility.bundleName)) {
214         HILOGE("the appId is different, check permission denied!");
215         return CALL_PERMISSION_DENIED;
216     }
217     // 3. check background permission
218     if (!CheckBackgroundPermission(targetAbility, callerInfo, want, false)) {
219         HILOGE("Check background permission failed!");
220         return DMS_BACKGROUND_PERMISSION_DENIED;
221     }
222     // 4.check application custom permissions
223     if (!CheckCustomPermission(targetAbility, callerInfo)) {
224         HILOGE("CheckCustomPermission denied or failed! the caller component do not have permission");
225         return DMS_COMPONENT_ACCESS_PERMISSION_DENIED;
226     }
227     HILOGI("CheckGetCallerPermission success!!");
228     return ERR_OK;
229 }
230 
IsFoundationCall() const231 bool DistributedSchedPermission::IsFoundationCall() const
232 {
233     uint32_t accessToken = IPCSkeleton::GetCallingTokenID();
234     AccessToken::NativeTokenInfo nativeTokenInfo;
235     int32_t result = AccessToken::AccessTokenKit::GetNativeTokenInfo(accessToken, nativeTokenInfo);
236     if (result == ERR_OK && nativeTokenInfo.processName == FOUNDATION_PROCESS_NAME) {
237         return true;
238     }
239     HILOGE("not foundation called, processName:%{private}s", nativeTokenInfo.processName.c_str());
240     return false;
241 }
242 
CheckPermission(uint32_t accessToken,const std::string & permissionName) const243 int32_t DistributedSchedPermission::CheckPermission(uint32_t accessToken, const std::string& permissionName) const
244 {
245     HILOGI("called.");
246     // if called from xts, granted directly, no need to check permissions.
247     if (IsNativeCall(accessToken)) {
248         return ERR_OK;
249     }
250     if (VerifyPermission(accessToken, permissionName)) {
251         return ERR_OK;
252     }
253     return DMS_PERMISSION_DENIED;
254 }
255 
IsNativeCall(uint32_t accessToken) const256 bool DistributedSchedPermission::IsNativeCall(uint32_t accessToken) const
257 {
258     auto tokenType = AccessToken::AccessTokenKit::GetTokenTypeFlag(accessToken);
259     if (tokenType == AccessToken::ATokenTypeEnum::TOKEN_NATIVE) {
260         return true;
261     }
262     return false;
263 }
264 
VerifyPermission(uint32_t accessToken,const std::string & permissionName) const265 bool DistributedSchedPermission::VerifyPermission(uint32_t accessToken, const std::string& permissionName) const
266 {
267     int32_t result = AccessToken::AccessTokenKit::VerifyAccessToken(accessToken, permissionName);
268     if (result == AccessToken::PermissionState::PERMISSION_DENIED) {
269         HILOGE("permission denied, permissionName:%{public}s", permissionName.c_str());
270         return false;
271     }
272     HILOGD("permission matched.");
273     return true;
274 }
275 
CheckAccountAccessPermission(const CallerInfo & callerInfo,const AccountInfo & accountInfo,const std::string & targetBundleName)276 bool DistributedSchedPermission::CheckAccountAccessPermission(const CallerInfo& callerInfo,
277     const AccountInfo& accountInfo, const std::string& targetBundleName)
278 {
279     if (accountInfo.accountType == IDistributedSched::SAME_ACCOUNT_TYPE) {
280         HILOGD("no need to check");
281         return true;
282     }
283     if (targetBundleName.empty() || accountInfo.groupIdList.empty()) {
284         HILOGE("targetBundleName or groupIdList is empty");
285         return false;
286     }
287 
288     for (const auto& groupId : accountInfo.groupIdList) {
289         HILOGD("groupId:%{public}s targetBundleName:%{public}s", groupId.c_str(), targetBundleName.c_str());
290         if (DistributedSchedAdapter::GetInstance().CheckAccessToGroup(groupId, targetBundleName)) {
291             return true;
292         }
293     }
294     HILOGE("check account permission failed");
295     return false;
296 }
297 
CheckComponentAccessPermission(const AppExecFwk::AbilityInfo & targetAbility,const CallerInfo & callerInfo,const AccountInfo & accountInfo,const AAFwk::Want & want) const298 bool DistributedSchedPermission::CheckComponentAccessPermission(const AppExecFwk::AbilityInfo& targetAbility,
299     const CallerInfo& callerInfo, const AccountInfo& accountInfo, const AAFwk::Want& want) const
300 {
301     // reject directly when in no account networking environment and target ability is not visible,
302     if (!targetAbility.visible) {
303         HILOGE("target ability is not visible, permission denied!");
304         return false;
305     }
306     HILOGD("check component permission success");
307     return true;
308 }
309 
CheckStartControlPermission(const AppExecFwk::AbilityInfo & targetAbility,const CallerInfo & callerInfo,const AAFwk::Want & want) const310 bool DistributedSchedPermission::CheckStartControlPermission(const AppExecFwk::AbilityInfo& targetAbility,
311     const CallerInfo& callerInfo, const AAFwk::Want& want) const
312 {
313     // 1. check if continuation with same appid
314     if ((want.GetFlags() & AAFwk::Want::FLAG_ABILITY_CONTINUATION) != 0) {
315         if (BundleManagerInternal::IsSameAppId(callerInfo.callerAppId, targetAbility.bundleName)) {
316             HILOGD("the appId is the same, check permission success!");
317             return true;
318         }
319         HILOGE("the appId is different in the migration scenario, permission denied!");
320         return false;
321     }
322     // 2. check background permission
323     if (!CheckBackgroundPermission(targetAbility, callerInfo, want, true)) {
324         HILOGE("Check background permission failed!");
325         return false;
326     }
327     // 3. check start or connect ability with same appid
328     if (BundleManagerInternal::IsSameAppId(callerInfo.callerAppId, targetAbility.bundleName)) {
329         HILOGD("the appId is the same, check permission success!");
330         return true;
331     }
332     // 4. check if target ability is not visible and without PERMISSION_START_INVISIBLE_ABILITY
333     if (!CheckTargetAbilityVisible(targetAbility, callerInfo)) {
334         HILOGE("target ability is not visible and has no PERMISSION_START_INVISIBLE_ABILITY, permission denied!");
335         return false;
336     }
337     // 5. check if service of fa mode can associatedWakeUp
338     if (!targetAbility.isStageBasedModel && targetAbility.type == AppExecFwk::AbilityType::SERVICE &&
339         !targetAbility.applicationInfo.associatedWakeUp) {
340         HILOGE("target ability is service ability(FA) and associatedWakeUp is false, permission denied!");
341         return false;
342     }
343     HILOGD("CheckStartControlPermission success");
344     return true;
345 }
346 
CheckCustomPermission(const AppExecFwk::AbilityInfo & targetAbility,const CallerInfo & callerInfo) const347 bool DistributedSchedPermission::CheckCustomPermission(const AppExecFwk::AbilityInfo& targetAbility,
348     const CallerInfo& callerInfo) const
349 {
350     const auto& permissions = targetAbility.permissions;
351     if (permissions.empty()) {
352         HILOGD("no need any permission, so granted!");
353         return true;
354     }
355     if (callerInfo.accessToken == 0) {
356         HILOGW("kernel is not support or field is not parsed, so denied!");
357         return false;
358     }
359     int64_t begin = GetTickCount();
360     uint32_t dAccessToken = AccessToken::AccessTokenKit::AllocLocalTokenID(callerInfo.sourceDeviceId,
361         callerInfo.accessToken);
362     HILOGI("[PerformanceTest] AllocLocalTokenID spend %{public}" PRId64 " ms", GetTickCount() - begin);
363     if (dAccessToken == 0) {
364         HILOGE("dAccessTokenID is invalid!");
365         return false;
366     }
367     for (const auto& permission : permissions) {
368         if (permission.empty()) {
369             continue;
370         }
371         int32_t result = AccessToken::AccessTokenKit::VerifyAccessToken(dAccessToken, permission);
372         if (result == AccessToken::PermissionState::PERMISSION_DENIED) {
373             HILOGD("dAccessTokenID:%{public}u, permission:%{public}s denied!", dAccessToken, permission.c_str());
374             return false;
375         }
376         HILOGD("dAccessTokenID:%{public}u, permission:%{public}s matched!", dAccessToken, permission.c_str());
377     }
378     return true;
379 }
380 
CheckBackgroundPermission(const AppExecFwk::AbilityInfo & targetAbility,const CallerInfo & callerInfo,const AAFwk::Want & want,bool needCheckApiVersion) const381 bool DistributedSchedPermission::CheckBackgroundPermission(const AppExecFwk::AbilityInfo& targetAbility,
382     const CallerInfo& callerInfo, const AAFwk::Want& want, bool needCheckApiVersion) const
383 {
384     if (callerInfo.extraInfoJson.empty() ||
385         callerInfo.extraInfoJson.find(DMS_VERSION_ID) == callerInfo.extraInfoJson.end()) {
386         HILOGD("the version is low");
387         return true;
388     }
389     AAFwk::Want* remoteWant = const_cast<Want*>(&want);
390     bool isCallerBackGround = remoteWant->GetBoolParam(DMS_IS_CALLER_BACKGROUND, true);
391     remoteWant->RemoveParam(DMS_IS_CALLER_BACKGROUND);
392     if (!isCallerBackGround) {
393         HILOGD("the app is foreground");
394         return true;
395     }
396     int apiVersion = remoteWant->GetIntParam(DMS_API_VERSION, DEFAULT_DMS_API_VERSION);
397     remoteWant->RemoveParam(DMS_API_VERSION);
398     // service in fa mode(API 8) do not need check
399     if (needCheckApiVersion && CheckMinApiVersion(targetAbility, apiVersion)) {
400         HILOGD("the app is service ability of fa mode and is under api 8");
401         return true;
402     }
403     uint32_t dAccessToken = AccessToken::AccessTokenKit::AllocLocalTokenID(callerInfo.sourceDeviceId,
404         callerInfo.accessToken);
405     if (dAccessToken == 0) {
406         HILOGE("dAccessTokenID is invalid!");
407         return false;
408     }
409     // check if background's ability has PERMISSION_START_ABILITIES_FROM_BACKGROUND
410     if (CheckPermission(dAccessToken, PERMISSION_START_ABILITIES_FROM_BACKGROUND) == ERR_OK ||
411         CheckPermission(dAccessToken, PERMISSION_START_ABILIIES_FROM_BACKGROUND) == ERR_OK) {
412         HILOGD("the app has PERMISSION_START_ABILITIES_FROM_BACKGROUND");
413         return true;
414     }
415     HILOGE("CheckBackgroundPermission failed!");
416     return false;
417 }
418 
CheckMinApiVersion(const AppExecFwk::AbilityInfo & targetAbility,int32_t apiVersion) const419 bool DistributedSchedPermission::CheckMinApiVersion(const AppExecFwk::AbilityInfo& targetAbility,
420     int32_t apiVersion) const
421 {
422     if (!targetAbility.isStageBasedModel && targetAbility.type == AppExecFwk::AbilityType::SERVICE &&
423         apiVersion <= FA_MODULE_ALLOW_MIN_API_VERSION) {
424         HILOGD("CheckMinApiVersion pass");
425         return true;
426     }
427     return false;
428 }
429 
CheckTargetAbilityVisible(const AppExecFwk::AbilityInfo & targetAbility,const CallerInfo & callerInfo) const430 bool DistributedSchedPermission::CheckTargetAbilityVisible(const AppExecFwk::AbilityInfo& targetAbility,
431     const CallerInfo& callerInfo) const
432 {
433     if (targetAbility.visible) {
434         HILOGD("Target ability is visible.");
435         return true;
436     }
437     uint32_t dAccessToken = AccessToken::AccessTokenKit::AllocLocalTokenID(callerInfo.sourceDeviceId,
438         callerInfo.accessToken);
439     if (dAccessToken == 0) {
440         HILOGE("dAccessTokenID is invalid!");
441         return false;
442     }
443     if (CheckPermission(dAccessToken, PERMISSION_START_INVISIBLE_ABILITY) != ERR_OK) {
444         HILOGE("CheckTargetAbilityVisible failed.");
445         return false;
446     }
447     HILOGD("CheckTargetAbilityVisible passed.");
448     return true;
449 }
450 }
451 }