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