• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 = &param};
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