1 /*
2 * Copyright (c) 2024 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 "uri_utils.h"
17
18 #include "ability_util.h"
19 #include "ability_config.h"
20 #include "ability_manager_errors.h"
21 #include "accesstoken_kit.h"
22 #include "extension_ability_info.h"
23 #include "hilog_tag_wrapper.h"
24 #include "in_process_call_wrapper.h"
25 #include "ipc_skeleton.h"
26 #include "tokenid_kit.h"
27 #include "ui_extension_utils.h"
28 #include "uri_permission_manager_client.h"
29
30 namespace OHOS {
31 namespace AAFwk {
32 namespace {
33 const std::string PARAMS_URI = "ability.verify.uri";
34 const std::string DISTRIBUTED_FILES_PATH = "/data/storage/el2/distributedfiles/";
35 const int32_t MAX_URI_COUNT = 500;
36 constexpr int32_t API13 = 13;
37 constexpr int32_t API_VERSION_MOD = 100;
38 constexpr uint32_t TOKEN_ID_BIT_SIZE = 32;
39 }
40
UriUtils()41 UriUtils::UriUtils() {}
42
~UriUtils()43 UriUtils::~UriUtils() {}
44
GetInstance()45 UriUtils &UriUtils::GetInstance()
46 {
47 static UriUtils utils;
48 return utils;
49 }
50
GetUriListFromWantDms(const Want &want)51 std::vector<std::string> UriUtils::GetUriListFromWantDms(const Want &want)
52 {
53 std::vector<std::string> uriVec = want.GetStringArrayParam(PARAMS_URI);
54 TAG_LOGD(AAFwkTag::ABILITYMGR, "uriVec size: %{public}zu", uriVec.size());
55 if (uriVec.size() > MAX_URI_COUNT) {
56 TAG_LOGE(AAFwkTag::ABILITYMGR, "uri list size is more than %{public}u", MAX_URI_COUNT);
57 return {};
58 }
59 std::vector<std::string> validUriVec;
60 for (auto &&str : uriVec) {
61 Uri uri(str);
62 auto &&scheme = uri.GetScheme();
63 TAG_LOGI(AAFwkTag::ABILITYMGR, "uri scheme: %{public}s", scheme.c_str());
64 // only support file scheme
65 if (scheme != "file") {
66 TAG_LOGW(AAFwkTag::ABILITYMGR, "only support file uri");
67 continue;
68 }
69 std::string srcPath = uri.GetPath();
70 if (std::filesystem::exists(srcPath) && std::filesystem::is_symlink(srcPath)) {
71 TAG_LOGE(AAFwkTag::ABILITYMGR, "soft links not allowed");
72 continue;
73 }
74 std::string absolutePath;
75 if (uri.IsRelative()) {
76 char path[PATH_MAX] = {0};
77 if (realpath(srcPath.c_str(), path) == nullptr) {
78 TAG_LOGE(AAFwkTag::ABILITYMGR, "fail, errno :%{public}d", errno);
79 continue;
80 }
81 absolutePath = path;
82 } else {
83 absolutePath = srcPath;
84 }
85 if (absolutePath.compare(0, DISTRIBUTED_FILES_PATH.size(), DISTRIBUTED_FILES_PATH) != 0) {
86 TAG_LOGE(AAFwkTag::ABILITYMGR, "uri not distributed path");
87 continue;
88 }
89 validUriVec.emplace_back(str);
90 }
91 TAG_LOGD(AAFwkTag::ABILITYMGR, "size of vaid uri is %{public}zu", validUriVec.size());
92 return validUriVec;
93 }
94
FilterUriWithPermissionDms(Want &want, uint32_t tokenId)95 void UriUtils::FilterUriWithPermissionDms(Want &want, uint32_t tokenId)
96 {
97 TAG_LOGD(AAFwkTag::ABILITYMGR, "called");
98 if ((want.GetFlags() & (Want::FLAG_AUTH_READ_URI_PERMISSION | Want::FLAG_AUTH_WRITE_URI_PERMISSION)) == 0) {
99 TAG_LOGW(AAFwkTag::ABILITYMGR, "flag invalid");
100 return;
101 }
102 auto uriVec = GetUriListFromWantDms(want);
103 TAG_LOGI(AAFwkTag::ABILITYMGR, "uri valid uris size: %{public}zu", uriVec.size());
104 if (uriVec.empty()) {
105 TAG_LOGI(AAFwkTag::ABILITYMGR, "uriVec empty");
106 want.SetParam(PARAMS_URI, uriVec);
107 return;
108 }
109 auto checkResult = IN_PROCESS_CALL(UriPermissionManagerClient::GetInstance().CheckUriAuthorization(
110 uriVec, want.GetFlags(), tokenId));
111 std::vector<std::string> validUriVec;
112 for (size_t i = 0; i < checkResult.size(); i++) {
113 if (checkResult[i]) {
114 validUriVec.emplace_back(uriVec[i]);
115 }
116 }
117 TAG_LOGI(AAFwkTag::ABILITYMGR, "authorized uri size :%{public}zu", validUriVec.size());
118 want.SetParam(PARAMS_URI, validUriVec);
119 }
120
CheckNonImplicitShareFileUri(const Want &want, int32_t userId, uint32_t specifyTokenId)121 int32_t UriUtils::CheckNonImplicitShareFileUri(const Want &want, int32_t userId, uint32_t specifyTokenId)
122 {
123 auto element = want.GetElement();
124 TAG_LOGD(AAFwkTag::ABILITYMGR, "CheckNonImplicitShareFileUri, %{public}s-%{public}s",
125 element.GetBundleName().c_str(), element.GetAbilityName().c_str());
126 if (element.GetBundleName().empty() || element.GetAbilityName().empty()) {
127 return ERR_OK;
128 }
129 if (!IsGrantUriPermissionFlag(want)) {
130 return ERR_OK;
131 }
132 bool isFileUri = (!want.GetUriString().empty() && want.GetUri().GetScheme() == "file");
133 if (!isFileUri && want.GetStringArrayParam(AbilityConfig::PARAMS_STREAM).empty()) {
134 TAG_LOGD(AAFwkTag::ABILITYMGR, "not file uri");
135 return ERR_OK;
136 }
137 // SA and system app support
138 auto callerTokenId = specifyTokenId > 0 ? specifyTokenId : IPCSkeleton::GetCallingTokenID();
139 return CheckNonImplicitShareFileUriInner(callerTokenId, element.GetBundleName(), userId);
140 }
141
CheckNonImplicitShareFileUriInner(uint32_t callerTokenId, const std::string &targetBundleName, int32_t userId)142 int32_t UriUtils::CheckNonImplicitShareFileUriInner(uint32_t callerTokenId, const std::string &targetBundleName,
143 int32_t userId)
144 {
145 auto tokenType = Security::AccessToken::AccessTokenKit::GetTokenTypeFlag(callerTokenId);
146 if (tokenType == Security::AccessToken::ATokenTypeEnum::TOKEN_NATIVE) {
147 TAG_LOGD(AAFwkTag::ABILITYMGR, "SA call");
148 return ERR_OK;
149 }
150 if (tokenType == Security::AccessToken::ATokenTypeEnum::TOKEN_HAP) {
151 Security::AccessToken::HapTokenInfo hapInfo;
152 auto ret = Security::AccessToken::AccessTokenKit::GetHapTokenInfo(callerTokenId, hapInfo);
153 if (ret != Security::AccessToken::AccessTokenKitRet::RET_SUCCESS) {
154 TAG_LOGE(AAFwkTag::URIPERMMGR, "GetHapTokenInfo failed, ret:%{public}d", ret);
155 return INNER_ERR;
156 }
157 // check api version
158 TAG_LOGD(AAFwkTag::ABILITYMGR, "CallerBundleName:%{public}s, API:%{public}d",
159 hapInfo.bundleName.c_str(), hapInfo.apiVersion);
160 if ((hapInfo.apiVersion % API_VERSION_MOD) < API13) {
161 TAG_LOGD(AAFwkTag::ABILITYMGR, "api version lower than 13");
162 return ERR_OK;
163 }
164 // check system app
165 uint64_t fullCallerTokenId = (static_cast<uint64_t>(hapInfo.tokenAttr) << TOKEN_ID_BIT_SIZE) + callerTokenId;
166 if (Security::AccessToken::TokenIdKit::IsSystemAppByFullTokenID(fullCallerTokenId)) {
167 TAG_LOGD(AAFwkTag::ABILITYMGR, "system app call");
168 return ERR_OK;
169 }
170 }
171 // target is system app
172 if (IsSystemApplication(targetBundleName, userId)) {
173 TAG_LOGD(AAFwkTag::ABILITYMGR, "target is system app");
174 return ERR_OK;
175 }
176 TAG_LOGE(AAFwkTag::ABILITYMGR, "Not allowed to share file uri non-implicitly");
177 return CHECK_PERMISSION_FAILED;
178 }
179
IsSystemApplication(const std::string &bundleName, int32_t userId)180 bool UriUtils::IsSystemApplication(const std::string &bundleName, int32_t userId)
181 {
182 auto bundleMgrHelper = AbilityUtil::GetBundleManagerHelper();
183 if (!bundleMgrHelper) {
184 TAG_LOGW(AAFwkTag::ABILITYMGR, "GetBundleManagerHelper failed");
185 return false;
186 }
187 AppExecFwk::ApplicationInfo appInfo;
188 if (!IN_PROCESS_CALL(bundleMgrHelper->GetApplicationInfo(bundleName,
189 AppExecFwk::BundleFlag::GET_BUNDLE_DEFAULT, userId, appInfo))) {
190 TAG_LOGW(AAFwkTag::ABILITYMGR, "GetApplicationInfo failed");
191 return false;
192 }
193 return appInfo.isSystemApp;
194 }
195
GetPermissionedUriList(const std::vector<std::string> &uriVec, const std::vector<bool> &checkResults, Want &want)196 std::vector<Uri> UriUtils::GetPermissionedUriList(const std::vector<std::string> &uriVec,
197 const std::vector<bool> &checkResults, Want &want)
198 {
199 std::vector<Uri> permissionedUris;
200 if (uriVec.size() != checkResults.size()) {
201 TAG_LOGE(AAFwkTag::ABILITYMGR, "Invalid param: %{public}zu : %{public}zu",
202 uriVec.size(), checkResults.size());
203 return permissionedUris;
204 }
205 // process uri
206 size_t startIndex = 0;
207 if (!want.GetUriString().empty()) {
208 if (checkResults[startIndex]) {
209 permissionedUris.emplace_back(want.GetUri());
210 } else if (want.GetUri().GetScheme() == "file") {
211 // erase uri param
212 want.SetUri("");
213 TAG_LOGI(AAFwkTag::ABILITYMGR, "erase uri param.");
214 }
215 startIndex = 1;
216 }
217 // process param stream
218 std::vector<std::string> paramStreamUris;
219 for (size_t index = startIndex; index < checkResults.size(); index++) {
220 auto uri = Uri(uriVec[index]);
221 if (checkResults[index]) {
222 permissionedUris.emplace_back(uri);
223 paramStreamUris.emplace_back(uriVec[index]);
224 } else if (uri.GetScheme() != "file") {
225 paramStreamUris.emplace_back(uriVec[index]);
226 }
227 }
228 if (paramStreamUris.size() != (checkResults.size() - startIndex)) {
229 // erase old param stream and set new param stream
230 want.RemoveParam(AbilityConfig::PARAMS_STREAM);
231 want.SetParam(AbilityConfig::PARAMS_STREAM, paramStreamUris);
232 TAG_LOGI(AAFwkTag::ABILITYMGR, "startIndex: %{public}zu, uriVec: %{public}zu, paramStreamUris: %{public}zu",
233 startIndex, uriVec.size(), paramStreamUris.size());
234 }
235 return permissionedUris;
236 }
237
GetUriListFromWant(Want &want, std::vector<std::string> &uriVec)238 bool UriUtils::GetUriListFromWant(Want &want, std::vector<std::string> &uriVec)
239 {
240 auto uriStr = want.GetUri().ToString();
241 uriVec = want.GetStringArrayParam(AbilityConfig::PARAMS_STREAM);
242 if (uriVec.empty() && uriStr.empty()) {
243 TAG_LOGW(AAFwkTag::ABILITYMGR, "uriVec empty.");
244 return false;
245 }
246 // process param stream
247 auto paramStreamUriCount = uriVec.size();
248 if (uriStr.empty() && paramStreamUriCount > MAX_URI_COUNT) {
249 TAG_LOGW(AAFwkTag::ABILITYMGR, "uri empty, paream stream counts: %{public}zu", paramStreamUriCount);
250 uriVec.resize(MAX_URI_COUNT);
251 want.RemoveParam(AbilityConfig::PARAMS_STREAM);
252 want.SetParam(AbilityConfig::PARAMS_STREAM, uriVec);
253 }
254 if (!uriStr.empty() && paramStreamUriCount > MAX_URI_COUNT - 1) {
255 TAG_LOGW(AAFwkTag::ABILITYMGR, "paream stream counts: %{public}zu", paramStreamUriCount);
256 uriVec.resize(MAX_URI_COUNT - 1);
257 want.RemoveParam(AbilityConfig::PARAMS_STREAM);
258 want.SetParam(AbilityConfig::PARAMS_STREAM, uriVec);
259 }
260 // process uri
261 if (!uriStr.empty()) {
262 uriVec.insert(uriVec.begin(), uriStr);
263 }
264 return true;
265 }
266
IsGrantUriPermissionFlag(const Want &want)267 bool UriUtils::IsGrantUriPermissionFlag(const Want &want)
268 {
269 return ((want.GetFlags() & (Want::FLAG_AUTH_READ_URI_PERMISSION | Want::FLAG_AUTH_WRITE_URI_PERMISSION)) != 0);
270 }
271
CheckUriPermissionForServiceExtension(Want &want, AppExecFwk::ExtensionAbilityType extensionAbilityType)272 void UriUtils::CheckUriPermissionForServiceExtension(Want &want, AppExecFwk::ExtensionAbilityType extensionAbilityType)
273 {
274 TAG_LOGD(AAFwkTag::ABILITYMGR, "CheckUriPermissionForServiceExtension called.");
275 if (extensionAbilityType != AppExecFwk::ExtensionAbilityType::SERVICE &&
276 extensionAbilityType != AppExecFwk::ExtensionAbilityType::UI_SERVICE) {
277 return;
278 }
279 CheckUriPermissionForExtension(want, 0);
280 return;
281 }
282
CheckUriPermissionForUIExtension(Want &want, AppExecFwk::ExtensionAbilityType extensionAbilityType, uint32_t tokenId)283 void UriUtils::CheckUriPermissionForUIExtension(Want &want, AppExecFwk::ExtensionAbilityType extensionAbilityType,
284 uint32_t tokenId)
285 {
286 TAG_LOGD(AAFwkTag::ABILITYMGR, "CheckUriPermissionForUIExtension called.");
287 if (!UIExtensionUtils::IsUIExtension(extensionAbilityType)) {
288 return;
289 }
290 CheckUriPermissionForExtension(want, tokenId);
291 return;
292 }
293
CheckUriPermissionForExtension(Want &want, uint32_t tokenId)294 void UriUtils::CheckUriPermissionForExtension(Want &want, uint32_t tokenId)
295 {
296 uint32_t flag = want.GetFlags();
297 if (!IsGrantUriPermissionFlag(want)) {
298 TAG_LOGD(AAFwkTag::ABILITYMGR, "No grant uri flag: %{public}u.", flag);
299 return;
300 }
301 std::vector<std::string> uriVec;
302 if (!UriUtils::GetUriListFromWant(want, uriVec)) {
303 TAG_LOGW(AAFwkTag::ABILITYMGR, "No file uri neet grant.");
304 return;
305 }
306 auto callerTokenId = tokenId > 0 ? tokenId : want.GetIntParam(Want::PARAM_RESV_CALLER_TOKEN, 0);
307 // check uri permission
308 auto checkResults = IN_PROCESS_CALL(UriPermissionManagerClient::GetInstance().CheckUriAuthorization(
309 uriVec, flag, callerTokenId));
310 // remove unpermissioned uri from want
311 UriUtils::GetInstance().GetPermissionedUriList(uriVec, checkResults, want);
312 return;
313 }
314
IsPermissionPreCheckedType(AppExecFwk::ExtensionAbilityType extensionAbilityType)315 bool UriUtils::IsPermissionPreCheckedType(AppExecFwk::ExtensionAbilityType extensionAbilityType)
316 {
317 return extensionAbilityType == AppExecFwk::ExtensionAbilityType::SERVICE ||
318 extensionAbilityType == AppExecFwk::ExtensionAbilityType::UI_SERVICE ||
319 UIExtensionUtils::IsUIExtension(extensionAbilityType);
320 }
321 } // AAFwk
322 } // OHOS
323