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 }