1 /*
2  * Copyright (c) 2023-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 #include "dlp_link_manager.h"
16 
17 #include "dlp_file.h"
18 #include "dlp_fuse_fd.h"
19 #include "dlp_permission.h"
20 #include "dlp_permission_log.h"
21 #include "fuse_daemon.h"
22 
23 namespace OHOS {
24 namespace Security {
25 namespace DlpPermission {
26 namespace {
27 static constexpr OHOS::HiviewDFX::HiLogLabel LABEL = {LOG_CORE, SECURITY_DOMAIN_DLP_PERMISSION, "DlpLinkManager"};
28 static const int MAX_FILE_NAME_LEN = 256;
29 static constexpr uint32_t MAX_DLP_LINK_SIZE = 1000; // max open link file
30 }
31 
DlpLinkManager()32 DlpLinkManager::DlpLinkManager()
33 {
34     FuseDaemon::InitFuseFs();
35 }
36 
~DlpLinkManager()37 DlpLinkManager::~DlpLinkManager()
38 {
39     Utils::UniqueWriteGuard<Utils::RWLock> infoGuard(g_DlpLinkMapLock_);
40     for (auto iter = g_DlpLinkFileNameMap_.begin(); iter != g_DlpLinkFileNameMap_.end();) {
41         DlpLinkFile* tmp = iter->second;
42         if (tmp != nullptr) {
43             iter = g_DlpLinkFileNameMap_.erase(iter);
44             delete tmp;
45         } else {
46             iter++;
47         }
48     }
49     CloseDlpFuseFd();
50 }
51 
IsLinkNameValid(const std::string & linkName)52 static bool IsLinkNameValid(const std::string& linkName)
53 {
54     size_t size = linkName.size();
55     return !(size == 0 || size > MAX_FILE_NAME_LEN);
56 }
57 
AddDlpLinkFile(std::shared_ptr<DlpFile> & filePtr,const std::string & dlpLinkName)58 int32_t DlpLinkManager::AddDlpLinkFile(std::shared_ptr<DlpFile>& filePtr, const std::string& dlpLinkName)
59 {
60     if (filePtr == nullptr) {
61         DLP_LOG_ERROR(LABEL, "Add link file fail, dlp file is null");
62         return DLP_FUSE_ERROR_DLP_FILE_NULL;
63     }
64     if (!IsLinkNameValid(dlpLinkName)) {
65         DLP_LOG_ERROR(LABEL, "Add link file fail, link file name %{public}s invalid", dlpLinkName.c_str());
66         return DLP_FUSE_ERROR_VALUE_INVALID;
67     }
68 
69     Utils::UniqueWriteGuard<Utils::RWLock> infoGuard(g_DlpLinkMapLock_);
70     if (g_DlpLinkFileNameMap_.size() >= MAX_DLP_LINK_SIZE) {
71         DLP_LOG_ERROR(LABEL, "Add link file fail, too many links");
72         return DLP_FUSE_ERROR_TOO_MANY_LINK_FILE;
73     }
74 
75     if (g_DlpLinkFileNameMap_.count(dlpLinkName) > 0) {
76         DLP_LOG_ERROR(LABEL, "Add link file fail, link file %{public}s exist", dlpLinkName.c_str());
77         return DLP_FUSE_ERROR_LINKFILE_EXIST;
78     }
79 
80     for (auto iter = g_DlpLinkFileNameMap_.begin(); iter != g_DlpLinkFileNameMap_.end(); iter++) {
81         DlpLinkFile* linkFileNode = iter->second;
82         if ((linkFileNode != nullptr) && (filePtr == linkFileNode->GetDlpFilePtr())) {
83             DLP_LOG_ERROR(LABEL, "Add link file fail, this dlp file already has link file");
84             return DLP_FUSE_ERROR_LINKFILE_EXIST;
85         }
86     }
87 
88     DlpLinkFile *node = new (std::nothrow) DlpLinkFile(dlpLinkName, filePtr);
89     if (node == nullptr) {
90         DLP_LOG_ERROR(LABEL, "Add link file fail, alloc link file %{public}s fail", dlpLinkName.c_str());
91         return DLP_FUSE_ERROR_MEMORY_OPERATE_FAIL;
92     }
93 
94     DLP_LOG_INFO(LABEL, "Add link file succ, file name %{public}s", dlpLinkName.c_str());
95     g_DlpLinkFileNameMap_[dlpLinkName] = node;
96     filePtr->SetLinkStatus();
97     return DLP_OK;
98 }
99 
StopDlpLinkFile(std::shared_ptr<DlpFile> & filePtr)100 int32_t DlpLinkManager::StopDlpLinkFile(std::shared_ptr<DlpFile>& filePtr)
101 {
102     if (filePtr == nullptr) {
103         DLP_LOG_ERROR(LABEL, "Stop link file fail, dlp file is null");
104         return DLP_FUSE_ERROR_DLP_FILE_NULL;
105     }
106 
107     Utils::UniqueWriteGuard<Utils::RWLock> infoGuard(g_DlpLinkMapLock_);
108     for (auto iter = g_DlpLinkFileNameMap_.begin(); iter != g_DlpLinkFileNameMap_.end(); iter++) {
109         DlpLinkFile* node = iter->second;
110         if (node == nullptr) {
111             DLP_LOG_ERROR(LABEL, "Stop link file fail, file ptr is null");
112             return DLP_FUSE_ERROR_DLP_FILE_NULL;
113         }
114         if (filePtr == node->GetDlpFilePtr()) {
115             node->stopLink();
116             filePtr->RemoveLinkStatus();
117             DLP_LOG_INFO(LABEL, "Stop link file success, file name %{public}s", node->GetLinkName().c_str());
118             return DLP_OK;
119         }
120     }
121     DLP_LOG_ERROR(LABEL, "Stop link file fail, link file not exist");
122     return DLP_FUSE_ERROR_LINKFILE_NOT_EXIST;
123 }
124 
RestartDlpLinkFile(std::shared_ptr<DlpFile> & filePtr)125 int32_t DlpLinkManager::RestartDlpLinkFile(std::shared_ptr<DlpFile>& filePtr)
126 {
127     if (filePtr == nullptr) {
128         DLP_LOG_ERROR(LABEL, "Restart link file fail, dlp file is null");
129         return DLP_FUSE_ERROR_DLP_FILE_NULL;
130     }
131 
132     Utils::UniqueWriteGuard<Utils::RWLock> infoGuard(g_DlpLinkMapLock_);
133     for (auto iter = g_DlpLinkFileNameMap_.begin(); iter != g_DlpLinkFileNameMap_.end(); iter++) {
134         DlpLinkFile* node = iter->second;
135         if (node == nullptr) {
136             DLP_LOG_ERROR(LABEL, "Restart link file fail, file ptr is null");
137             return DLP_FUSE_ERROR_DLP_FILE_NULL;
138         }
139         if (filePtr == node->GetDlpFilePtr()) {
140             node->restartLink();
141             filePtr->SetLinkStatus();
142             DLP_LOG_INFO(LABEL, "Restart link file success, file name %{public}s", node->GetLinkName().c_str());
143             return DLP_OK;
144         }
145     }
146     DLP_LOG_ERROR(LABEL, "Restart link file fail, link file not exist");
147     return DLP_FUSE_ERROR_LINKFILE_NOT_EXIST;
148 }
149 
ReplaceDlpLinkFile(std::shared_ptr<DlpFile> & filePtr,const std::string & dlpLinkName)150 int32_t DlpLinkManager::ReplaceDlpLinkFile(std::shared_ptr<DlpFile>& filePtr, const std::string& dlpLinkName)
151 {
152     if (filePtr == nullptr) {
153         DLP_LOG_ERROR(LABEL, "Replace link file fail, dlp file is null");
154         return DLP_FUSE_ERROR_DLP_FILE_NULL;
155     }
156     if (!IsLinkNameValid(dlpLinkName)) {
157         DLP_LOG_ERROR(LABEL, "Replace link file fail, link file name %{public}s invalid", dlpLinkName.c_str());
158         return DLP_FUSE_ERROR_VALUE_INVALID;
159     }
160 
161     Utils::UniqueWriteGuard<Utils::RWLock> infoGuard(g_DlpLinkMapLock_);
162     for (auto iter = g_DlpLinkFileNameMap_.begin(); iter != g_DlpLinkFileNameMap_.end(); iter++) {
163         if (dlpLinkName == iter->first) {
164             DlpLinkFile *node = iter->second;
165             if (node == nullptr) {
166                 DLP_LOG_ERROR(
167                     LABEL, "Replace link file fail, file %{public}s found but file ptr is null", dlpLinkName.c_str());
168                 return DLP_FUSE_ERROR_DLP_FILE_NULL;
169             }
170             node->setDlpFilePtr(filePtr);
171             DLP_LOG_INFO(LABEL, "Replace link file success, file name %{public}s", dlpLinkName.c_str());
172             return DLP_OK;
173         }
174     }
175     DLP_LOG_ERROR(LABEL, "Replace link file fail, file %{public}s not exist", dlpLinkName.c_str());
176     return DLP_FUSE_ERROR_LINKFILE_NOT_EXIST;
177 }
178 
DeleteDlpLinkFile(std::shared_ptr<DlpFile> & filePtr)179 int32_t DlpLinkManager::DeleteDlpLinkFile(std::shared_ptr<DlpFile>& filePtr)
180 {
181     if (filePtr == nullptr) {
182         return DLP_FUSE_ERROR_DLP_FILE_NULL;
183     }
184 
185     Utils::UniqueWriteGuard<Utils::RWLock> infoGuard(g_DlpLinkMapLock_);
186     for (auto iter = g_DlpLinkFileNameMap_.begin(); iter != g_DlpLinkFileNameMap_.end(); iter++) {
187         DlpLinkFile* tmp = iter->second;
188         if (tmp != nullptr && filePtr == tmp->GetDlpFilePtr()) {
189             filePtr->RemoveLinkStatus();
190             g_DlpLinkFileNameMap_.erase(iter);
191             if (tmp->SubAndCheckZeroRef(1)) {
192                 DLP_LOG_INFO(LABEL, "Delete link file %{private}s ok", tmp->GetLinkName().c_str());
193                 delete tmp;
194             } else {
195                 DLP_LOG_INFO(LABEL, "Link file %{private}s is still referenced by kernel, only remove it from map",
196                     tmp->GetLinkName().c_str());
197             }
198             return DLP_OK;
199         }
200     }
201     DLP_LOG_ERROR(LABEL, "Delete link file fail, it does not exist.");
202     return DLP_FUSE_ERROR_LINKFILE_NOT_EXIST;
203 }
204 
LookUpDlpLinkFile(const std::string & dlpLinkName)205 DlpLinkFile* DlpLinkManager::LookUpDlpLinkFile(const std::string& dlpLinkName)
206 {
207     Utils::UniqueReadGuard<Utils::RWLock> infoGuard(g_DlpLinkMapLock_);
208     for (auto iter = g_DlpLinkFileNameMap_.begin(); iter != g_DlpLinkFileNameMap_.end(); ++iter) {
209         if (dlpLinkName == iter->first) {
210             DlpLinkFile* node = iter->second;
211             if (node == nullptr) {
212                 DLP_LOG_ERROR(LABEL, "Look up link file fail, file %{public}s found but file ptr is null",
213                     dlpLinkName.c_str());
214                 return nullptr;
215             }
216             node->IncreaseRef();
217             return node;
218         }
219     }
220     DLP_LOG_ERROR(LABEL, "Look up link file fail, file %{public}s not exist", dlpLinkName.c_str());
221     return nullptr;
222 }
223 
DumpDlpLinkFile(std::vector<DlpLinkFileInfo> & linkList)224 void DlpLinkManager::DumpDlpLinkFile(std::vector<DlpLinkFileInfo>& linkList)
225 {
226     Utils::UniqueReadGuard<Utils::RWLock> infoGuard(g_DlpLinkMapLock_);
227     for (auto iter = g_DlpLinkFileNameMap_.begin(); iter != g_DlpLinkFileNameMap_.end(); iter++) {
228         DlpLinkFile* filePtr = iter->second;
229         if (filePtr == nullptr) {
230             continue;
231         }
232         DlpLinkFileInfo info;
233         info.dlpLinkName = filePtr->GetLinkName();
234         info.fileStat = filePtr->GetLinkStat();
235         linkList.emplace_back(info);
236     }
237 }
238 
GetInstance()239 DlpLinkManager& DlpLinkManager::GetInstance()
240 {
241     static DlpLinkManager instance;
242     return instance;
243 }
244 }  // namespace DlpPermission
245 }  // namespace Security
246 }  // namespace OHOS
247