1 /*
2 * Copyright (c) 2023 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 "sandbox_json_manager.h"
17
18 #include "appexecfwk_errors.h"
19 #include "bundle_mgr_client.h"
20 #include "dlp_permission_log.h"
21 #include "dlp_permission.h"
22 #include "ipc_skeleton.h"
23 #include "iservice_registry.h"
24 #include "i_json_operator.h"
25 #include "os_account_manager.h"
26 #include "system_ability_definition.h"
27
28 namespace OHOS {
29 namespace Security {
30 namespace DlpPermission {
31 using namespace Security::AccessToken;
32 using Json = nlohmann::json;
33 using namespace OHOS;
34 namespace {
35 const std::string APPINDEX = "appIndex";
36 const std::string BUNDLENAME = "bundleName";
37 const std::string DOCURISET = "docUriSet";
38 const std::string USERID = "userId";
39 const std::string TOKENID = "tokenId";
40 const std::string DLPFILEACCESS = "dlpFileAccess";
41 const std::string HAS_READ = "hasRead";
42 static const uint32_t MAX_RETENTION_SIZE = 1024;
43 static constexpr OHOS::HiviewDFX::HiLogLabel LABEL = { LOG_CORE, SECURITY_DOMAIN_DLP_PERMISSION, "SandboxJsonManager" };
44 }
45
46 typedef enum KeyType {
47 NUMBER,
48 STRING,
49 ARRAY,
50 BOOL,
51 } KeyType;
52
SandboxJsonManager()53 SandboxJsonManager::SandboxJsonManager()
54 {
55 infoVec_.clear();
56 }
57
~SandboxJsonManager()58 SandboxJsonManager::~SandboxJsonManager()
59 {
60 infoVec_.clear();
61 }
62
HasRetentionSandboxInfo(const std::string & bundleName)63 bool SandboxJsonManager::HasRetentionSandboxInfo(const std::string& bundleName)
64 {
65 int32_t userId;
66 if (!GetUserIdByForegroundAccount(&userId)) {
67 return false;
68 }
69 std::lock_guard<std::mutex> lock(mutex_);
70 for (auto iter = infoVec_.begin(); iter != infoVec_.end(); ++iter) {
71 if (iter->bundleName == bundleName && iter->userId == userId) {
72 return true;
73 }
74 }
75 return false;
76 }
77
AddSandboxInfo(const RetentionInfo & retentionInfo)78 int32_t SandboxJsonManager::AddSandboxInfo(const RetentionInfo& retentionInfo)
79 {
80 if (retentionInfo.bundleName.empty() || retentionInfo.appIndex < 0 || retentionInfo.userId < 0 ||
81 retentionInfo.tokenId == 0) {
82 DLP_LOG_ERROR(LABEL, "Param is invalid, bundleName.empty=%{public}d, appIndex=%{public}d, userId=%{public}d"
83 ", userId=%{public}d.", retentionInfo.bundleName.empty(), retentionInfo.appIndex, retentionInfo.userId,
84 retentionInfo.tokenId);
85 return DLP_INSERT_FILE_ERROR;
86 }
87 if (InsertSandboxInfo(retentionInfo)) {
88 return DLP_OK;
89 }
90 return DLP_INSERT_FILE_ERROR;
91 }
92
CanUninstall(const uint32_t & tokenId)93 bool SandboxJsonManager::CanUninstall(const uint32_t& tokenId)
94 {
95 std::lock_guard<std::mutex> lock(mutex_);
96 for (auto iter = infoVec_.begin(); iter != infoVec_.end(); ++iter) {
97 if (iter->tokenId == tokenId) {
98 if (iter->docUriSet.empty()) {
99 return true;
100 }
101 return false;
102 }
103 }
104 return true;
105 }
106
DelSandboxInfo(const uint32_t & tokenId)107 int32_t SandboxJsonManager::DelSandboxInfo(const uint32_t& tokenId)
108 {
109 std::lock_guard<std::mutex> lock(mutex_);
110 for (auto iter = infoVec_.begin(); iter != infoVec_.end(); ++iter) {
111 if (iter->tokenId == tokenId) {
112 if (iter->docUriSet.empty()) {
113 infoVec_.erase(iter);
114 return DLP_OK;
115 }
116 DLP_LOG_ERROR(LABEL, "docUriset not empty tokenId:%{public}d", tokenId);
117 return DLP_RETENTION_SERVICE_ERROR;
118 }
119 }
120 DLP_LOG_ERROR(LABEL, "docUri not exist tokenId:%{public}d", tokenId);
121 return DLP_RETENTION_SERVICE_ERROR;
122 }
123
UpdateRetentionState(const std::set<std::string> & docUriSet,RetentionInfo & info,bool isRetention)124 int32_t SandboxJsonManager::UpdateRetentionState(const std::set<std::string>& docUriSet, RetentionInfo& info,
125 bool isRetention)
126 {
127 if (docUriSet.empty()) {
128 return DLP_OK;
129 }
130 if (isRetention) {
131 if (info.tokenId == 0) {
132 DLP_LOG_ERROR(LABEL, "tokenId==0");
133 return DLP_RETENTION_UPDATE_ERROR;
134 }
135 return UpdateRetentionState(docUriSet, info, CompareByTokenId, UpdateDocUriSetByUnion);
136 }
137 if (info.bundleName.empty() && info.tokenId == 0) {
138 DLP_LOG_ERROR(LABEL, "tokenId==0 and bundleName empty");
139 return DLP_RETENTION_UPDATE_ERROR;
140 }
141 GetUserIdByUid(info.userId);
142 if (info.tokenId == 0) {
143 return UpdateRetentionState(docUriSet, info, CompareByBundleName, ClearDocUriSet);
144 }
145 return UpdateRetentionState(docUriSet, info, CompareByTokenId, ClearDocUriSet);
146 }
147
CompareByTokenId(const RetentionInfo & info1,const RetentionInfo & info2)148 bool SandboxJsonManager::CompareByTokenId(const RetentionInfo& info1, const RetentionInfo& info2)
149 {
150 return info1.tokenId == info2.tokenId;
151 }
152
CompareByBundleName(const RetentionInfo & info1,const RetentionInfo & info2)153 bool SandboxJsonManager::CompareByBundleName(const RetentionInfo& info1, const RetentionInfo& info2)
154 {
155 return info1.bundleName == info2.bundleName && info1.userId == info2.userId;
156 }
157
UpdateDocUriSetByUnion(RetentionInfo & info,const std::set<std::string> & newSet)158 bool SandboxJsonManager::UpdateDocUriSetByUnion(RetentionInfo& info, const std::set<std::string>& newSet)
159 {
160 std::set<std::string> temp;
161 std::set_union(info.docUriSet.begin(), info.docUriSet.end(), newSet.begin(), newSet.end(),
162 std::insert_iterator<std::set<std::string>>(temp, temp.begin()));
163 if (temp.size() > MAX_RETENTION_SIZE) {
164 DLP_LOG_ERROR(LABEL, "size bigger than MAX_RETENTION_SIZE");
165 return false;
166 }
167 bool isUpdate = info.docUriSet.size() != temp.size();
168 info.docUriSet = temp;
169 return isUpdate;
170 }
171
ClearDocUriSet(RetentionInfo & info,const std::set<std::string> & newSet)172 bool SandboxJsonManager::ClearDocUriSet(RetentionInfo& info, const std::set<std::string>& newSet)
173 {
174 if (info.docUriSet.empty()) {
175 DLP_LOG_INFO(LABEL, "docUriSet size=0 ");
176 return false;
177 }
178 info.docUriSet.clear();
179 return true;
180 }
181
UpdateRetentionState(const std::set<std::string> & newSet,const RetentionInfo & info,bool (* compare)(const RetentionInfo & info1,const RetentionInfo & info2),bool (* update)(RetentionInfo & info,const std::set<std::string> & newSet))182 int32_t SandboxJsonManager::UpdateRetentionState(const std::set<std::string>& newSet, const RetentionInfo& info,
183 bool (*compare)(const RetentionInfo& info1, const RetentionInfo& info2),
184 bool (*update)(RetentionInfo& info, const std::set<std::string>& newSet))
185 {
186 std::lock_guard<std::mutex> lock(mutex_);
187 bool isUpdate = false;
188 for (auto iter = infoVec_.begin(); iter != infoVec_.end(); ++iter) {
189 if (!compare(*iter, info)) {
190 continue;
191 }
192 if (update(*iter, newSet)) {
193 isUpdate = true;
194 }
195 if (info.hasRead == true) {
196 iter->hasRead = true;
197 isUpdate = true;
198 }
199 }
200 if (!isUpdate) {
201 DLP_LOG_ERROR(LABEL, "not update : %{public}s", info.bundleName.c_str());
202 return DLP_FILE_NO_NEED_UPDATE;
203 }
204 return DLP_OK;
205 }
206
UpdateReadFlag(uint32_t tokenId)207 int32_t SandboxJsonManager::UpdateReadFlag(uint32_t tokenId)
208 {
209 std::lock_guard<std::mutex> lock(mutex_);
210 for (auto iter = infoVec_.begin(); iter != infoVec_.end(); ++iter) {
211 if (tokenId == iter->tokenId && !iter->docUriSet.empty()) {
212 iter->hasRead = true;
213 return DLP_OK;
214 }
215 }
216 DLP_LOG_ERROR(LABEL, "Not update tokenId=%{public}u", tokenId);
217 return DLP_FILE_NO_NEED_UPDATE;
218 }
219
RemoveRetentionState(const std::string & bundleName,const int32_t & appIndex)220 int32_t SandboxJsonManager::RemoveRetentionState(const std::string& bundleName, const int32_t& appIndex)
221 {
222 bool hasBundleName = false;
223 {
224 int32_t userId;
225 if (!GetUserIdByForegroundAccount(&userId)) {
226 return false;
227 }
228 std::lock_guard<std::mutex> lock(mutex_);
229 for (auto iter = infoVec_.begin(); iter != infoVec_.end();) {
230 if (iter->bundleName == bundleName && iter->userId == userId) {
231 if (appIndex != -1 && iter->appIndex != appIndex) {
232 ++iter;
233 continue;
234 }
235 iter = infoVec_.erase(iter);
236 hasBundleName = true;
237 } else {
238 ++iter;
239 }
240 }
241 }
242
243 if (!hasBundleName) {
244 DLP_LOG_ERROR(LABEL, "failed to find bundleName : %{public}s", bundleName.c_str());
245 return DLP_RETENTION_GET_DATA_FROM_BASE_CONSTRAINTS_FILE_EMPTY;
246 }
247 return DLP_OK;
248 }
249
GetRetentionSandboxList(const std::string & bundleName,std::vector<RetentionSandBoxInfo> & retentionSandBoxInfoVec,bool isRetention)250 int32_t SandboxJsonManager::GetRetentionSandboxList(const std::string& bundleName,
251 std::vector<RetentionSandBoxInfo>& retentionSandBoxInfoVec, bool isRetention)
252 {
253 std::lock_guard<std::mutex> lock(mutex_);
254 if (infoVec_.empty()) {
255 return DLP_OK;
256 }
257
258 int32_t userId;
259 if (!GetUserIdByUid(userId)) {
260 return DLP_RETENTION_SERVICE_ERROR;
261 }
262 for (auto iter = infoVec_.begin(); iter != infoVec_.end(); ++iter) {
263 if (iter->bundleName != bundleName || iter->userId != userId) {
264 continue;
265 }
266 if (isRetention && iter->docUriSet.empty()) {
267 continue;
268 }
269 if (!isRetention && !iter->docUriSet.empty()) {
270 continue;
271 }
272 RetentionSandBoxInfo info;
273 info.bundleName_ = bundleName;
274 info.appIndex_ = iter->appIndex;
275 info.docUriSet_ = iter->docUriSet;
276 info.dlpFileAccess_ = iter->dlpFileAccess;
277 info.hasRead_ = iter->hasRead;
278 retentionSandBoxInfoVec.push_back(info);
279 }
280 return DLP_OK;
281 }
282
ClearUnreservedSandbox()283 int32_t SandboxJsonManager::ClearUnreservedSandbox()
284 {
285 DLP_LOG_INFO(LABEL, "ClearUnreservedSandbox called");
286 int32_t userId;
287 if (!GetUserIdByForegroundAccount(&userId)) {
288 return false;
289 }
290 std::lock_guard<std::mutex> lock(mutex_);
291 bool isChanged = false;
292 AppExecFwk::BundleMgrClient bundleMgrClient;
293 for (auto iter = infoVec_.begin(); iter != infoVec_.end();) {
294 if (!iter->docUriSet.empty() || iter->userId != userId) {
295 ++iter;
296 continue;
297 }
298 int32_t res = bundleMgrClient.UninstallSandboxApp(iter->bundleName, iter->appIndex, iter->userId);
299 if (res != DLP_OK && res != ERR_APPEXECFWK_SANDBOX_INSTALL_NO_SANDBOX_APP_INFO) {
300 DLP_LOG_ERROR(LABEL, "uninstall sandbox %{public}s fail, index=%{public}d, error=%{public}d",
301 iter->bundleName.c_str(), iter->appIndex, res);
302 ++iter;
303 continue;
304 }
305 DLP_LOG_DEBUG(LABEL, "uninstall sandbox %{public}s success, index=%{public}d, error=%{public}d",
306 iter->bundleName.c_str(), iter->appIndex, res);
307 iter = infoVec_.erase(iter);
308 isChanged = true;
309 }
310 if (!isChanged) {
311 DLP_LOG_INFO(LABEL, "do not need update");
312 return DLP_FILE_NO_NEED_UPDATE;
313 }
314 return DLP_OK;
315 }
316
GetUserIdByUid(int32_t & userId)317 bool SandboxJsonManager::GetUserIdByUid(int32_t& userId)
318 {
319 int32_t uid = IPCSkeleton::GetCallingUid();
320 return GetUserIdFromUid(uid, &userId) == 0;
321 }
322
GetBundleNameSetByUserId(const int32_t userId,std::set<std::string> & bundleNameSet)323 int32_t SandboxJsonManager::GetBundleNameSetByUserId(const int32_t userId, std::set<std::string>& bundleNameSet)
324 {
325 std::lock_guard<std::mutex> lock(mutex_);
326 if (infoVec_.empty()) {
327 return DLP_OK;
328 }
329 for (auto iter = infoVec_.begin(); iter != infoVec_.end(); ++iter) {
330 if (iter->userId == userId) {
331 bundleNameSet.emplace(iter->bundleName);
332 }
333 }
334 return DLP_OK;
335 }
336
RemoveRetentionInfoByUserId(const int32_t userId,const std::set<std::string> & bundleNameSet)337 int32_t SandboxJsonManager::RemoveRetentionInfoByUserId(const int32_t userId,
338 const std::set<std::string>& bundleNameSet)
339 {
340 bool isNeedUpdate = false;
341 AppExecFwk::BundleMgrClient bundleMgrClient;
342 std::lock_guard<std::mutex> lock(mutex_);
343 for (auto iter = infoVec_.begin(); iter != infoVec_.end();) {
344 if ((iter->userId != userId) ||
345 ((bundleNameSet.count(iter->bundleName) == 0) && !CheckReInstall(*iter, userId))) {
346 ++iter;
347 continue;
348 }
349 int32_t res = bundleMgrClient.UninstallSandboxApp(iter->bundleName, iter->appIndex, iter->userId);
350 if (res != DLP_OK && res != ERR_APPEXECFWK_SANDBOX_INSTALL_NO_SANDBOX_APP_INFO) {
351 DLP_LOG_ERROR(LABEL, "uninstall sandbox %{public}s fail, index=%{public}d, error=%{public}d",
352 iter->bundleName.c_str(), iter->appIndex, res);
353 ++iter;
354 continue;
355 }
356 DLP_LOG_DEBUG(LABEL, "uninstall sandbox %{public}s success, index=%{public}d, error=%{public}d",
357 iter->bundleName.c_str(), iter->appIndex, res);
358 iter = infoVec_.erase(iter);
359 isNeedUpdate = true;
360 }
361 if (!isNeedUpdate) {
362 DLP_LOG_INFO(LABEL, "do not need update");
363 return DLP_FILE_NO_NEED_UPDATE;
364 }
365 return DLP_OK;
366 }
367
CheckReInstall(const RetentionInfo & info,const int32_t userId)368 bool SandboxJsonManager::CheckReInstall(const RetentionInfo& info, const int32_t userId)
369 {
370 uint32_t tokenId = AccessToken::AccessTokenKit::GetHapTokenID(userId, info.bundleName, info.appIndex);
371 if (tokenId == info.tokenId) {
372 return false;
373 }
374 DLP_LOG_ERROR(LABEL, "GetHapTokenID not equal %{public}s,%{public}d", info.bundleName.c_str(), info.appIndex);
375 return true;
376 }
377
InsertSandboxInfo(const RetentionInfo & info)378 bool SandboxJsonManager::InsertSandboxInfo(const RetentionInfo& info)
379 {
380 std::lock_guard<std::mutex> lock(mutex_);
381 for (auto iter = infoVec_.begin(); iter != infoVec_.end(); ++iter) {
382 if (iter->tokenId == info.tokenId) {
383 DLP_LOG_ERROR(LABEL, "DocUri exist bundleName:%{public}s, appIndex:%{public}d",
384 info.bundleName.c_str(), info.appIndex);
385 return false;
386 }
387 }
388 infoVec_.push_back(info);
389 return true;
390 }
391
RetentionInfoToJson(Json & json,const RetentionInfo & info) const392 void SandboxJsonManager::RetentionInfoToJson(Json& json, const RetentionInfo& info) const
393 {
394 json = Json { { APPINDEX, info.appIndex },
395 { TOKENID, info.tokenId },
396 { BUNDLENAME, info.bundleName },
397 { USERID, info.userId },
398 { DLPFILEACCESS, info.dlpFileAccess },
399 { DOCURISET, info.docUriSet },
400 { HAS_READ, info.hasRead } };
401 }
402
ToJson() const403 Json SandboxJsonManager::ToJson() const
404 {
405 std::lock_guard<std::mutex> lock(mutex_);
406 Json jsonObject;
407 for (auto iter = infoVec_.begin(); iter != infoVec_.end(); ++iter) {
408 Json infoJson;
409 RetentionInfoToJson(infoJson, *iter);
410 jsonObject["retention"].push_back(infoJson);
411 }
412 return jsonObject;
413 }
414
CheckJsonElement(const std::string & key,const Json & retentionJson,const KeyType & keyType)415 static bool CheckJsonElement(const std::string& key, const Json& retentionJson, const KeyType& keyType)
416 {
417 switch (keyType) {
418 case KeyType::NUMBER:
419 return retentionJson.contains(key) && retentionJson.at(key).is_number();
420 case KeyType::STRING:
421 return retentionJson.contains(key) && retentionJson.at(key).is_string();
422 case KeyType::ARRAY:
423 return retentionJson.contains(key) && retentionJson.at(key).is_array();
424 case KeyType::BOOL:
425 return retentionJson.contains(key) && retentionJson.at(key).is_boolean();
426 default:
427 return false;
428 }
429 return false;
430 }
431
FromJson(const Json & jsonObject)432 void SandboxJsonManager::FromJson(const Json& jsonObject)
433 {
434 if (jsonObject.is_null() || jsonObject.is_discarded()) {
435 DLP_LOG_ERROR(LABEL, "json error");
436 return;
437 }
438 for (auto& retentionJson : jsonObject["retention"]) {
439 RetentionInfo info;
440 if (!CheckJsonElement(APPINDEX, retentionJson, KeyType::NUMBER) ||
441 !CheckJsonElement(BUNDLENAME, retentionJson, KeyType::STRING) ||
442 !CheckJsonElement(TOKENID, retentionJson, KeyType::NUMBER) ||
443 !CheckJsonElement(DOCURISET, retentionJson, KeyType::ARRAY) ||
444 !CheckJsonElement(USERID, retentionJson, KeyType::NUMBER) ||
445 !CheckJsonElement(DLPFILEACCESS, retentionJson, KeyType::NUMBER) ||
446 !CheckJsonElement(HAS_READ, retentionJson, KeyType::BOOL)) {
447 DLP_LOG_ERROR(LABEL, "json contains error");
448 continue;
449 }
450 retentionJson.at(APPINDEX).get_to(info.appIndex);
451 retentionJson.at(BUNDLENAME).get_to(info.bundleName);
452 retentionJson.at(DOCURISET).get_to(info.docUriSet);
453 retentionJson.at(TOKENID).get_to(info.tokenId);
454 retentionJson.at(DLPFILEACCESS).get_to(info.dlpFileAccess);
455 retentionJson.at(USERID).get_to(info.userId);
456 retentionJson.at(HAS_READ).get_to(info.hasRead);
457 if (info.bundleName.empty() || info.appIndex < 0 || info.userId < 0 || info.tokenId == 0) {
458 DLP_LOG_ERROR(LABEL, "param is invalid");
459 return;
460 }
461 InsertSandboxInfo(info);
462 }
463 }
464
ToString() const465 std::string SandboxJsonManager::ToString() const
466 {
467 {
468 std::lock_guard<std::mutex> lock(mutex_);
469 if (infoVec_.empty()) {
470 return "";
471 }
472 }
473 auto jsonObject = ToJson();
474 return jsonObject.dump();
475 }
476 } // namespace DlpPermission
477 } // namespace Security
478 } // namespace OHOS
479