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 #include "dlp_file_manager.h"
16
17 #include <dirent.h>
18 #include <cstdio>
19 #include <sys/stat.h>
20 #include <sys/types.h>
21 #include <unistd.h>
22
23 #include "dlp_crypt.h"
24 #include "dlp_file.h"
25 #include "dlp_permission.h"
26 #include "dlp_permission_kit.h"
27 #include "dlp_permission_log.h"
28 #include "hitrace_meter.h"
29 #include "securec.h"
30
31 namespace OHOS {
32 namespace Security {
33 namespace DlpPermission {
34 namespace {
35 static constexpr OHOS::HiviewDFX::HiLogLabel LABEL = {LOG_CORE, SECURITY_DOMAIN_DLP_PERMISSION, "DlpFileManager"};
36 static constexpr uint32_t MAX_DLP_FILE_SIZE = 1000; // max open dlp file
37 }
38
AddDlpFileNode(const std::shared_ptr<DlpFile> & filePtr)39 int32_t DlpFileManager::AddDlpFileNode(const std::shared_ptr<DlpFile>& filePtr)
40 {
41 Utils::UniqueWriteGuard<Utils::RWLock> infoGuard(this->g_DlpMapLock_);
42 if (g_DlpFileMap_.size() >= MAX_DLP_FILE_SIZE) {
43 DLP_LOG_ERROR(LABEL, "Add dlp file node failed, too many files");
44 return DLP_PARSE_ERROR_TOO_MANY_OPEN_DLP_FILE;
45 }
46 if (g_DlpFileMap_.count(filePtr->dlpFd_) > 0) {
47 DLP_LOG_ERROR(LABEL, "Add dlp file node fail, fd %{public}d already exist", filePtr->dlpFd_);
48 return DLP_PARSE_ERROR_FILE_ALREADY_OPENED;
49 }
50 g_DlpFileMap_[filePtr->dlpFd_] = filePtr;
51 return DLP_OK;
52 }
53
RemoveDlpFileNode(const std::shared_ptr<DlpFile> & filePtr)54 int32_t DlpFileManager::RemoveDlpFileNode(const std::shared_ptr<DlpFile>& filePtr)
55 {
56 Utils::UniqueWriteGuard<Utils::RWLock> infoGuard(this->g_DlpMapLock_);
57 for (auto iter = g_DlpFileMap_.begin(); iter != g_DlpFileMap_.end(); iter++) {
58 if (filePtr->dlpFd_ == iter->first) {
59 g_DlpFileMap_.erase(iter);
60 return DLP_OK;
61 }
62 }
63
64 DLP_LOG_ERROR(LABEL, "Remove dlp file node fail, fd %{public}d not exist", filePtr->dlpFd_);
65 return DLP_PARSE_ERROR_FILE_NOT_OPENED;
66 }
67
GetDlpFile(int32_t dlpFd)68 std::shared_ptr<DlpFile> DlpFileManager::GetDlpFile(int32_t dlpFd)
69 {
70 Utils::UniqueReadGuard<Utils::RWLock> infoGuard(this->g_DlpMapLock_);
71 for (auto iter = g_DlpFileMap_.begin(); iter != g_DlpFileMap_.end(); iter++) {
72 if (dlpFd == iter->first) {
73 return iter->second;
74 }
75 }
76
77 return nullptr;
78 }
79
GenerateCertData(const PermissionPolicy & policy,struct DlpBlob & certData) const80 int32_t DlpFileManager::GenerateCertData(const PermissionPolicy& policy, struct DlpBlob& certData) const
81 {
82 std::vector<uint8_t> cert;
83 StartTrace(HITRACE_TAG_ACCESS_CONTROL, "DlpGenerateCertificate");
84 int32_t result = DlpPermissionKit::GenerateDlpCertificate(policy, cert);
85 FinishTrace(HITRACE_TAG_ACCESS_CONTROL);
86 if (result != DLP_OK) {
87 DLP_LOG_ERROR(LABEL, "Generate dlp cert fail, errno=%{public}d", result);
88 return result;
89 }
90 return GenerateCertBlob(cert, certData);
91 }
92
GenerateCertBlob(const std::vector<uint8_t> & cert,struct DlpBlob & certData) const93 int32_t DlpFileManager::GenerateCertBlob(const std::vector<uint8_t>& cert, struct DlpBlob& certData) const
94 {
95 size_t certSize = cert.size();
96 if (certSize > DLP_MAX_CERT_SIZE) {
97 DLP_LOG_ERROR(LABEL, "Check dlp cert fail, cert is too large, size=%{public}zu", certSize);
98 return DLP_PARSE_ERROR_VALUE_INVALID;
99 }
100 if (certSize == 0) {
101 DLP_LOG_ERROR(LABEL, "Check dlp cert fail, cert is zero, size=%{public}zu", certSize);
102 return DLP_PARSE_ERROR_VALUE_INVALID;
103 }
104
105 uint8_t* certBuffer = new (std::nothrow) uint8_t[certSize];
106 if (certBuffer == nullptr) {
107 DLP_LOG_ERROR(LABEL, "Copy dlp cert fail, alloc buff fail");
108 return DLP_PARSE_ERROR_MEMORY_OPERATE_FAIL;
109 }
110
111 if (memcpy_s(certBuffer, certSize, &cert[0], certSize) != EOK) {
112 DLP_LOG_ERROR(LABEL, "Copy dlp cert fail, memcpy_s fail");
113 delete[] certBuffer;
114 return DLP_PARSE_ERROR_MEMORY_OPERATE_FAIL;
115 }
116
117 certData.data = certBuffer;
118 certData.size = static_cast<uint32_t>(certSize);
119 return DLP_OK;
120 }
121
CleanTempBlob(struct DlpBlob & key,struct DlpCipherParam * tagIv,struct DlpBlob & hmacKey) const122 void DlpFileManager::CleanTempBlob(struct DlpBlob& key, struct DlpCipherParam* tagIv, struct DlpBlob& hmacKey) const
123 {
124 if (key.data != nullptr) {
125 delete[] key.data;
126 key.data = nullptr;
127 }
128 if (tagIv != nullptr) {
129 if (tagIv->iv.data != nullptr) {
130 delete[] tagIv->iv.data;
131 tagIv->iv.data = nullptr;
132 }
133 delete tagIv;
134 tagIv = nullptr;
135 }
136 if (hmacKey.data != nullptr) {
137 delete[] hmacKey.data;
138 hmacKey.data = nullptr;
139 }
140 }
141
PrepareDlpEncryptParms(PermissionPolicy & policy,struct DlpBlob & key,struct DlpUsageSpec & usage,struct DlpBlob & certData,struct DlpBlob & hmacKey) const142 int32_t DlpFileManager::PrepareDlpEncryptParms(PermissionPolicy& policy, struct DlpBlob& key,
143 struct DlpUsageSpec& usage, struct DlpBlob& certData, struct DlpBlob& hmacKey) const
144 {
145 DLP_LOG_INFO(LABEL, "Generate key");
146 int32_t res = DlpOpensslGenerateRandomKey(DLP_AES_KEY_SIZE_256, &key);
147 if (res != DLP_OK) {
148 DLP_LOG_ERROR(LABEL, "Generate key fail, errno=%{public}d", res);
149 return res;
150 }
151
152 struct DlpCipherParam* tagIv = new (std::nothrow) struct DlpCipherParam;
153 if (tagIv == nullptr) {
154 DLP_LOG_ERROR(LABEL, "Alloc iv buff fail");
155 CleanTempBlob(key, tagIv, hmacKey);
156 return DLP_PARSE_ERROR_MEMORY_OPERATE_FAIL;
157 }
158 DLP_LOG_INFO(LABEL, "Generate iv");
159 res = DlpOpensslGenerateRandomKey(IV_SIZE * BIT_NUM_OF_UINT8, &tagIv->iv);
160 if (res != DLP_OK) {
161 DLP_LOG_ERROR(LABEL, "Generate iv fail, errno=%{public}d", res);
162 CleanTempBlob(key, tagIv, hmacKey);
163 return res;
164 }
165
166 DLP_LOG_INFO(LABEL, "Generate hmac key");
167 res = DlpOpensslGenerateRandomKey(DLP_AES_KEY_SIZE_256, &hmacKey);
168 if (res != DLP_OK) {
169 DLP_LOG_ERROR(LABEL, "Generate hmacKey fail, errno=%{public}d", res);
170 CleanTempBlob(key, tagIv, hmacKey);
171 return res;
172 }
173
174 usage.mode = DLP_MODE_CTR;
175 usage.algParam = tagIv;
176 policy.SetAeskey(key.data, key.size);
177 policy.SetIv(tagIv->iv.data, tagIv->iv.size);
178 policy.SetHmacKey(hmacKey.data, hmacKey.size);
179
180 DLP_LOG_INFO(LABEL, "Generate cert");
181 res = GenerateCertData(policy, certData);
182 if (res != DLP_OK) {
183 DLP_LOG_ERROR(LABEL, "Generate cert fail, errno=%{public}d", res);
184 CleanTempBlob(key, tagIv, hmacKey);
185 return res;
186 }
187
188 return DLP_OK;
189 }
190
UpdateDlpFile(bool isNeedAdapter,uint32_t oldCertSize,const std::string & workDir,const std::vector<uint8_t> & cert,std::shared_ptr<DlpFile> & filePtr)191 int32_t DlpFileManager::UpdateDlpFile(bool isNeedAdapter, uint32_t oldCertSize, const std::string& workDir,
192 const std::vector<uint8_t>& cert, std::shared_ptr<DlpFile>& filePtr)
193 {
194 std::lock_guard<std::mutex> lock(g_offlineLock_);
195 int32_t result = filePtr->CheckDlpFile();
196 if (result != DLP_OK) {
197 return result;
198 }
199 struct DlpBlob certBlob;
200 #ifdef SUPPORT_DLP_CREDENTIAL
201 result = GenerateCertBlob(cert, certBlob);
202 if (result != DLP_OK) {
203 return result;
204 }
205 #else
206 return DLP_OK;
207 #endif
208 if (isNeedAdapter || oldCertSize != certBlob.size) {
209 return filePtr->UpdateCertAndText(cert, workDir, certBlob);
210 }
211 return filePtr->UpdateCert(certBlob);
212 }
213
ParseDlpFileFormat(std::shared_ptr<DlpFile> & filePtr,const std::string & workDir,const std::string & appId)214 int32_t DlpFileManager::ParseDlpFileFormat(std::shared_ptr<DlpFile>& filePtr, const std::string& workDir,
215 const std::string& appId)
216 {
217 int32_t result = filePtr->ParseDlpHeader();
218 if (result != DLP_OK) {
219 return result;
220 }
221 struct DlpBlob cert;
222 filePtr->GetEncryptCert(cert);
223 sptr<CertParcel> certParcel = new (std::nothrow) CertParcel();
224 if (certParcel == nullptr) {
225 DLP_LOG_ERROR(LABEL, "Alloc certParcel parcel fail");
226 return DLP_PARSE_ERROR_MEMORY_OPERATE_FAIL;
227 }
228 certParcel->cert = std::vector<uint8_t>(cert.data, cert.data + cert.size);
229 uint32_t oldCertSize = cert.size;
230 struct DlpBlob offlineCert = { 0 };
231 uint32_t flag = filePtr->GetOfflineAccess();
232 if (flag != 0) {
233 filePtr->GetOfflineCert(offlineCert);
234 certParcel->offlineCert = std::vector<uint8_t>(offlineCert.data, offlineCert.data + offlineCert.size);
235 }
236 PermissionPolicy policy;
237 filePtr->GetContactAccount(certParcel->contactAccount);
238 certParcel->isNeedAdapter = filePtr->NeedAdapter();
239 StartTrace(HITRACE_TAG_ACCESS_CONTROL, "DlpParseCertificate");
240 result = DlpPermissionKit::ParseDlpCertificate(certParcel, policy, appId, filePtr->GetOfflineAccess());
241 FinishTrace(HITRACE_TAG_ACCESS_CONTROL);
242 if (result != DLP_OK) {
243 DLP_LOG_ERROR(LABEL, "Parse cert fail, errno=%{public}d", result);
244 return result;
245 }
246 result = filePtr->SetPolicy(policy);
247 if (result != DLP_OK) {
248 return result;
249 }
250 struct DlpBlob key = {.size = policy.GetAeskeyLen(), .data = policy.GetAeskey()};
251 struct DlpCipherParam param = {.iv = {.size = policy.GetIvLen(), .data = policy.GetIv()}};
252 struct DlpUsageSpec usage = {.mode = DLP_MODE_CTR, .algParam = ¶m};
253 struct DlpBlob hmacKey = {.size = policy.GetHmacKeyLen(), .data = policy.GetHmacKey()};
254 result = filePtr->SetCipher(key, usage, hmacKey);
255 if (result != DLP_OK) {
256 return result;
257 }
258 result = filePtr->HmacCheck();
259 if (result != DLP_OK) {
260 return result;
261 }
262 return UpdateDlpFile(filePtr->NeedAdapter(), oldCertSize, workDir, certParcel->offlineCert, filePtr);
263 }
264
FreeChiperBlob(struct DlpBlob & key,struct DlpBlob & certData,struct DlpUsageSpec & usage,struct DlpBlob & hmacKey) const265 void DlpFileManager::FreeChiperBlob(struct DlpBlob& key, struct DlpBlob& certData,
266 struct DlpUsageSpec& usage, struct DlpBlob& hmacKey) const
267 {
268 if (key.data != nullptr) {
269 delete[] key.data;
270 key.data = nullptr;
271 }
272
273 if (certData.data != nullptr) {
274 delete[] certData.data;
275 certData.data = nullptr;
276 }
277 if (usage.algParam != nullptr) {
278 if (usage.algParam->iv.data != nullptr) {
279 delete[] usage.algParam->iv.data;
280 usage.algParam->iv.data = nullptr;
281 }
282 delete usage.algParam;
283 usage.algParam = nullptr;
284 }
285
286 if (hmacKey.data != nullptr) {
287 delete[] hmacKey.data;
288 hmacKey.data = nullptr;
289 }
290 }
291
SetDlpFileParams(std::shared_ptr<DlpFile> & filePtr,const DlpProperty & property) const292 int32_t DlpFileManager::SetDlpFileParams(std::shared_ptr<DlpFile>& filePtr, const DlpProperty& property) const
293 {
294 PermissionPolicy policy(property);
295 struct DlpBlob key;
296 struct DlpBlob certData;
297 struct DlpUsageSpec usage;
298 struct DlpBlob hmacKey;
299
300 int32_t result = PrepareDlpEncryptParms(policy, key, usage, certData, hmacKey);
301 if (result != DLP_OK) {
302 DLP_LOG_ERROR(LABEL, "Set dlp obj params fail, prepare encrypt params error, errno=%{public}d", result);
303 return result;
304 }
305 result = filePtr->SetCipher(key, usage, hmacKey);
306 if (result != DLP_OK) {
307 FreeChiperBlob(key, certData, usage, hmacKey);
308 DLP_LOG_ERROR(LABEL, "Set dlp obj params fail, set cipher error, errno=%{public}d", result);
309 return result;
310 }
311
312 result = filePtr->SetPolicy(policy);
313 if (result != DLP_OK) {
314 FreeChiperBlob(key, certData, usage, hmacKey);
315 DLP_LOG_ERROR(LABEL, "Set dlp obj params fail, set policy error, errno=%{public}d", result);
316 return result;
317 }
318
319 result = filePtr->SetEncryptCert(certData);
320 if (result != DLP_OK) {
321 FreeChiperBlob(key, certData, usage, hmacKey);
322 DLP_LOG_ERROR(LABEL, "Set dlp obj params fail, set cert error, errno=%{public}d", result);
323 return result;
324 }
325
326 result = filePtr->SetContactAccount(property.contactAccount);
327 if (result != DLP_OK) {
328 DLP_LOG_WARN(LABEL, "Set dlp obj params fail, set contact account error, errno=%{public}d", result);
329 }
330
331 filePtr->SetOfflineAccess(property.offlineAccess);
332
333 FreeChiperBlob(key, certData, usage, hmacKey);
334 return result;
335 }
336
RemoveDirRecursive(const char * path)337 static bool RemoveDirRecursive(const char *path)
338 {
339 DIR *dir = opendir(path);
340 if (dir == nullptr) {
341 return false;
342 }
343
344 dirent *entry;
345 while ((entry = readdir(dir)) != nullptr) {
346 if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0) {
347 continue;
348 }
349 std::string subPath = std::string(path) + "/" + entry->d_name;
350 if (entry->d_type == DT_DIR) {
351 if (!RemoveDirRecursive(subPath.c_str())) {
352 closedir(dir);
353 return false;
354 }
355 } else {
356 if (remove(subPath.c_str()) != 0) {
357 closedir(dir);
358 return false;
359 }
360 }
361 }
362
363 closedir(dir);
364
365 if (rmdir(path) != 0) {
366 DLP_LOG_ERROR(LABEL, "rmdir fail, errno %{public}s", strerror(errno));
367 return false;
368 }
369 return true;
370 }
371
372 std::mutex g_dirCleanLock;
PrepareDirs(const std::string & path)373 static void PrepareDirs(const std::string& path)
374 {
375 std::lock_guard<std::mutex> lock(g_dirCleanLock);
376 static bool cleanOnce = true;
377 if (cleanOnce) {
378 cleanOnce = false;
379 RemoveDirRecursive(path.c_str());
380 mkdir(path.c_str(), S_IRWXU);
381 }
382 }
383
384
GenerateDlpFile(int32_t plainFileFd,int32_t dlpFileFd,const DlpProperty & property,std::shared_ptr<DlpFile> & filePtr,const std::string & workDir)385 int32_t DlpFileManager::GenerateDlpFile(
386 int32_t plainFileFd, int32_t dlpFileFd, const DlpProperty& property, std::shared_ptr<DlpFile>& filePtr,
387 const std::string& workDir)
388 {
389 if (plainFileFd < 0 || dlpFileFd < 0) {
390 DLP_LOG_ERROR(LABEL, "Generate dlp file fail, plain file fd or dlp file fd invalid");
391 return DLP_PARSE_ERROR_FD_ERROR;
392 }
393
394 if (GetDlpFile(dlpFileFd) != nullptr) {
395 DLP_LOG_ERROR(LABEL, "Generate dlp file fail, dlp file has generated, if you want to rebuild, close it first");
396 return DLP_PARSE_ERROR_FILE_ALREADY_OPENED;
397 }
398
399 std::string cache = workDir + "/cache";
400 PrepareDirs(cache);
401 filePtr = std::make_shared<DlpFile>(dlpFileFd, cache, ++index_, true);
402
403 int32_t result = SetDlpFileParams(filePtr, property);
404 if (result != DLP_OK) {
405 DLP_LOG_ERROR(LABEL, "Generate dlp file fail, set dlp obj params error, errno=%{public}d", result);
406 return result;
407 }
408
409 result = filePtr->GenFile(plainFileFd);
410 if (result != DLP_OK) {
411 DLP_LOG_ERROR(LABEL, "Generate dlp file fail, errno=%{public}d", result);
412 return result;
413 }
414
415 return AddDlpFileNode(filePtr);
416 }
417
OpenDlpFile(int32_t dlpFileFd,std::shared_ptr<DlpFile> & filePtr,const std::string & workDir,const std::string & appId)418 int32_t DlpFileManager::OpenDlpFile(int32_t dlpFileFd, std::shared_ptr<DlpFile>& filePtr, const std::string& workDir,
419 const std::string& appId)
420 {
421 if (dlpFileFd < 0) {
422 DLP_LOG_ERROR(LABEL, "Open dlp file fail, fd %{public}d is invalid", dlpFileFd);
423 return DLP_PARSE_ERROR_FD_ERROR;
424 }
425
426 filePtr = GetDlpFile(dlpFileFd);
427 if (filePtr != nullptr) {
428 DLP_LOG_INFO(LABEL, "Open dlp file fail, fd %{public}d has opened", dlpFileFd);
429 return DLP_OK;
430 }
431
432 std::string cache = workDir + "/cache";
433 PrepareDirs(cache);
434 filePtr = std::make_shared<DlpFile>(dlpFileFd, cache, ++index_, false);
435
436 int32_t result = ParseDlpFileFormat(filePtr, workDir, appId);
437 if (result != DLP_OK) {
438 DLP_LOG_ERROR(LABEL, "Open dlp file fail, parse dlp file error, errno=%{public}d", result);
439 return result;
440 }
441
442 return AddDlpFileNode(filePtr);
443 }
444
CloseDlpFile(const std::shared_ptr<DlpFile> & dlpFile)445 int32_t DlpFileManager::CloseDlpFile(const std::shared_ptr<DlpFile>& dlpFile)
446 {
447 if (dlpFile == nullptr) {
448 DLP_LOG_ERROR(LABEL, "Close dlp file fail, dlp obj is null");
449 return DLP_PARSE_ERROR_PTR_NULL;
450 }
451
452 return RemoveDlpFileNode(dlpFile);
453 }
454
RecoverDlpFile(std::shared_ptr<DlpFile> & filePtr,int32_t plainFd) const455 int32_t DlpFileManager::RecoverDlpFile(std::shared_ptr<DlpFile>& filePtr, int32_t plainFd) const
456 {
457 if (filePtr == nullptr) {
458 DLP_LOG_ERROR(LABEL, "Recover dlp file fail, dlp obj is null");
459 return DLP_PARSE_ERROR_PTR_NULL;
460 }
461 if (plainFd < 0) {
462 DLP_LOG_ERROR(LABEL, "Recover dlp file fail, fd %{public}d is invalid", plainFd);
463 return DLP_PARSE_ERROR_FD_ERROR;
464 }
465
466 return filePtr->RemoveDlpPermission(plainFd);
467 }
468
GetInstance()469 DlpFileManager& DlpFileManager::GetInstance()
470 {
471 static DlpFileManager instance;
472 return instance;
473 }
474 } // namespace DlpPermission
475 } // namespace Security
476 } // namespace OHOS
477