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 
16 #include "fuse_daemon.h"
17 
18 #include <pthread.h>
19 #include <securec.h>
20 #include <sys/stat.h>
21 #include <sys/types.h>
22 #include <unistd.h>
23 #include <vector>
24 #include "dlp_fuse_fd.h"
25 #include "dlp_link_file.h"
26 #include "dlp_link_manager.h"
27 #include "dlp_permission.h"
28 #include "dlp_permission_log.h"
29 
30 namespace OHOS {
31 namespace Security {
32 namespace DlpPermission {
33 namespace {
34 static constexpr OHOS::HiviewDFX::HiLogLabel LABEL = {LOG_CORE, SECURITY_DOMAIN_DLP_PERMISSION, "FuseDaemon"};
35 static constexpr int ROOT_INODE = 1;
36 static constexpr int DEFAULT_ATTR_TIMEOUT = 10000;
37 static constexpr int MAX_FILE_NAME_LEN = 256;
38 static constexpr int ROOT_INODE_ACCESS = 0711;
39 static constexpr uint32_t MAX_READ_DIR_BUF_SIZE = 100 * 1024;  // 100K
40 static constexpr const char* CUR_DIR = ".";
41 static constexpr const char* UPPER_DIR = "..";
42 static constexpr const char* THREAD_OS_DLP_FUSE = "OS_DLP_FUSE";
43 }  // namespace
44 
45 std::condition_variable FuseDaemon::daemonEnableCv_;
46 enum DaemonStatus FuseDaemon::daemonStatus_;
47 std::mutex FuseDaemon::daemonEnableMtx_;
48 struct stat FuseDaemon::rootFileStat_;
49 bool FuseDaemon::init_ = false;
50 
51 // caller need to check ino == ROOT_INODE
GetFileNode(fuse_ino_t ino)52 static DlpLinkFile* GetFileNode(fuse_ino_t ino)
53 {
54     return reinterpret_cast<DlpLinkFile*>(static_cast<uintptr_t>(ino));
55 }
56 
GetFileInode(DlpLinkFile * node)57 fuse_ino_t GetFileInode(DlpLinkFile* node)
58 {
59     return static_cast<fuse_ino_t>(reinterpret_cast<uintptr_t>(node));
60 }
61 
FuseDaemonLookup(fuse_req_t req,fuse_ino_t parent,const char * name)62 static void FuseDaemonLookup(fuse_req_t req, fuse_ino_t parent, const char* name)
63 {
64     if (name == nullptr) {
65         DLP_LOG_ERROR(LABEL, "Look up link file fail, name is null");
66         fuse_reply_err(req, ENOENT);
67         return;
68     }
69     DLP_LOG_DEBUG(LABEL, "Look up link file, name=%{private}s", name);
70 
71     if (parent != ROOT_INODE) {
72         DLP_LOG_ERROR(LABEL, "Look up link file fail, parent is not root inode");
73         fuse_reply_err(req, ENOENT);
74         return;
75     }
76 
77     struct fuse_entry_param fep;
78     (void)memset_s(&fep, sizeof(struct fuse_entry_param), 0, sizeof(struct fuse_entry_param));
79     if (!strcmp(name, ".") || !strcmp(name, "..")) {
80         fep.ino = ROOT_INODE;
81         fep.attr = *(FuseDaemon::GetRootFileStat());
82         fuse_reply_entry(req, &fep);
83         return;
84     }
85 
86     std::string nameStr = name;
87     DlpLinkFile* node = DlpLinkManager::GetInstance().LookUpDlpLinkFile(nameStr);
88     if (node == nullptr) {
89         DLP_LOG_ERROR(LABEL, "Look up link file fail, file %{public}s can not found", name);
90         fuse_reply_err(req, ENOENT);
91     } else {
92         DLP_LOG_DEBUG(LABEL, "Look up link file succ, file %{public}s found", name);
93         fep.ino = GetFileInode(node);
94         fep.attr = node->GetLinkStat();
95         fuse_reply_entry(req, &fep);
96     }
97 }
98 
UpdateCurrTimeStat(struct timespec * ts)99 void UpdateCurrTimeStat(struct timespec* ts)
100 {
101     clock_gettime(CLOCK_REALTIME, ts);
102 }
103 
FuseDaemonGetattr(fuse_req_t req,fuse_ino_t ino,struct fuse_file_info * fi)104 static void FuseDaemonGetattr(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info* fi)
105 {
106     (void)fi;
107 
108     if (ino == ROOT_INODE) {
109         struct stat* fileStat = FuseDaemon::GetRootFileStat();
110         fuse_reply_attr(req, fileStat, DEFAULT_ATTR_TIMEOUT);
111         return;
112     }
113 
114     DlpLinkFile* dlp = GetFileNode(ino);
115     if (dlp == nullptr) {
116         DLP_LOG_ERROR(LABEL, "Get link file attr fail, wrong ino");
117         fuse_reply_err(req, ENOENT);
118         return;
119     }
120 
121     struct stat fileStat = dlp->GetLinkStat();
122     fuse_reply_attr(req, &fileStat, DEFAULT_ATTR_TIMEOUT);
123 }
124 
125 // we will handle open flag later
FuseDaemonOpen(fuse_req_t req,fuse_ino_t ino,struct fuse_file_info * fi)126 static void FuseDaemonOpen(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info* fi)
127 {
128     if (ino == ROOT_INODE) {
129         DLP_LOG_ERROR(LABEL, "Open link file fail, can not open root dir");
130         fuse_reply_err(req, ENOENT);
131         return;
132     }
133 
134     DlpLinkFile* dlp = GetFileNode(ino);
135     if (dlp == nullptr) {
136         DLP_LOG_ERROR(LABEL, "Open link file fail, wrong ino");
137         fuse_reply_err(req, ENOENT);
138         return;
139     }
140     if ((fi != nullptr) && (static_cast<uint32_t>(fi->flags) & O_TRUNC) != 0) {
141         int32_t ret = dlp->Truncate(0);
142         if (ret != DLP_OK) {
143             DLP_LOG_ERROR(LABEL, "Open link file with truncate fail, ret=%{public}d", ret);
144             fuse_reply_err(req, EINVAL);
145             return;
146         }
147         DLP_LOG_INFO(LABEL, "Open link file with truncate succ");
148     }
149 
150     fuse_reply_open(req, fi);
151     dlp->UpdateAtimeStat();
152 }
153 
GetValidFileNode(fuse_req_t req,fuse_ino_t ino)154 static DlpLinkFile* GetValidFileNode(fuse_req_t req, fuse_ino_t ino)
155 {
156     if (ino == ROOT_INODE) {
157         fuse_reply_err(req, ENOENT);
158         return nullptr;
159     }
160     DlpLinkFile* dlp = GetFileNode(ino);
161     if (dlp == nullptr) {
162         fuse_reply_err(req, EBADF);
163         return nullptr;
164     }
165     return dlp;
166 }
167 
FuseDaemonRead(fuse_req_t req,fuse_ino_t ino,size_t size,off_t offset,struct fuse_file_info * fi)168 static void FuseDaemonRead(fuse_req_t req, fuse_ino_t ino, size_t size, off_t offset, struct fuse_file_info* fi)
169 {
170     (void)fi;
171     if (req == nullptr) {
172         DLP_LOG_ERROR(LABEL, "Fuse_req_t is nullptr");
173         fuse_reply_err(req, EINVAL);
174         return;
175     }
176     if (offset < 0 || offset > DLP_MAX_CONTENT_SIZE) {
177         fuse_reply_err(req, EINVAL);
178         return;
179     }
180     if (size > DLP_FUSE_MAX_BUFFLEN) {
181         DLP_LOG_ERROR(LABEL, "Read link file fail, read size %{public}zu too large", size);
182         fuse_reply_err(req, EINVAL);
183         return;
184     }
185     DlpLinkFile* dlp = GetValidFileNode(req, ino);
186     if (dlp == nullptr) {
187         DLP_LOG_ERROR(LABEL, "Read link file fail, wrong ino");
188         return;
189     }
190 
191     char* buf = reinterpret_cast<char*>(malloc(size));
192     if (buf == nullptr) {
193         DLP_LOG_ERROR(LABEL, "Read link file fail, malloc %{public}zu buff fail", size);
194         fuse_reply_err(req, EINVAL);
195         return;
196     }
197     (void)memset_s(buf, size, 0, size);
198     int32_t res = dlp->Read(static_cast<uint32_t>(offset), buf, static_cast<uint32_t>(size), req->ctx.uid);
199     if (res < 0) {
200         fuse_reply_err(req, EIO);
201     } else {
202         fuse_reply_buf(req, buf, static_cast<size_t>(res));
203     }
204     DLP_LOG_DEBUG(LABEL, "Read file name %{private}s offset %{public}u size %{public}u res %{public}d",
205         dlp->GetLinkName().c_str(), static_cast<uint32_t>(offset), static_cast<uint32_t>(size), res);
206     free(buf);
207 }
208 
FuseDaemonWrite(fuse_req_t req,fuse_ino_t ino,const char * buf,size_t size,off_t off,struct fuse_file_info * fi)209 static void FuseDaemonWrite(
210     fuse_req_t req, fuse_ino_t ino, const char* buf, size_t size, off_t off, struct fuse_file_info* fi)
211 {
212     (void)fi;
213     if (off < 0 || off > DLP_MAX_CONTENT_SIZE) {
214         fuse_reply_err(req, EINVAL);
215         return;
216     }
217     if (size > DLP_FUSE_MAX_BUFFLEN) {
218         DLP_LOG_ERROR(LABEL, "Write link file fail, write size %{public}zu too large", size);
219         fuse_reply_err(req, EINVAL);
220         return;
221     }
222     DlpLinkFile* dlp = GetValidFileNode(req, ino);
223     if (dlp == nullptr) {
224         DLP_LOG_ERROR(LABEL, "Write link file fail, wrong ino");
225         return;
226     }
227     int32_t res = dlp->Write(static_cast<uint32_t>(off),
228         const_cast<void *>(static_cast<const void *>(buf)), static_cast<uint32_t>(size));
229     if (res < 0) {
230         fuse_reply_err(req, EIO);
231     } else {
232         fuse_reply_write(req, static_cast<size_t>(res));
233     }
234     DLP_LOG_DEBUG(LABEL, "Write file name %{private}s offset %{public}u size %{public}u res %{public}d",
235         dlp->GetLinkName().c_str(), static_cast<uint32_t>(off), static_cast<uint32_t>(size), res);
236 }
237 
FuseDaemonForget(fuse_req_t req,fuse_ino_t ino,uint64_t nlookup)238 static void FuseDaemonForget(fuse_req_t req, fuse_ino_t ino, uint64_t nlookup)
239 {
240     if (ino == ROOT_INODE) {
241         DLP_LOG_WARN(LABEL, "Forget root dir is forbidden");
242         fuse_reply_err(req, ENOENT);
243         return;
244     }
245 
246     DlpLinkFile* dlp = GetFileNode(ino);
247     if (dlp == nullptr) {
248         DLP_LOG_ERROR(LABEL, "Forgot link file fail, wrong ino");
249         fuse_reply_err(req, EBADF);
250         return;
251     }
252     DLP_LOG_DEBUG(LABEL, "Forget link file name %{private}s nlookup %{public}u",
253         dlp->GetLinkName().c_str(), static_cast<uint32_t>(nlookup));
254     if (dlp->SubAndCheckZeroRef(nlookup)) {
255         DLP_LOG_INFO(LABEL, "Link file reference is less than 0, delete link file ok");
256         delete dlp;
257     }
258 }
259 
AddDirentry(DirAddParams & param)260 static int AddDirentry(DirAddParams& param)
261 {
262     size_t shouldSize = fuse_add_direntry(param.req, nullptr, 0, param.entryName.c_str(), nullptr, 0);
263     if (shouldSize > param.bufLen) {
264         return -1;
265     }
266     param.curOff = param.nextOff;
267     size_t addSize = fuse_add_direntry(param.req, param.directBuf, param.bufLen,
268         param.entryName.c_str(), param.entryStat, param.curOff);
269     param.directBuf += addSize;
270     param.bufLen -= addSize;
271     param.nextOff += static_cast<int>(addSize);
272     return 0;
273 }
274 
AddRootDirentry(DirAddParams & params)275 static int AddRootDirentry(DirAddParams& params)
276 {
277     struct stat* rootStat = FuseDaemon::GetRootFileStat();
278     params.entryName = CUR_DIR;
279     params.entryStat = rootStat;
280 
281     if (AddDirentry(params) != 0) {
282         fuse_reply_err(params.req, EINVAL);
283         return -1;
284     }
285 
286     params.entryName = UPPER_DIR;
287     if (AddDirentry(params) != 0) {
288         fuse_reply_err(params.req, EINVAL);
289         return -1;
290     }
291     return 0;
292 }
293 
AddLinkFilesDirentry(DirAddParams & params)294 static int AddLinkFilesDirentry(DirAddParams& params)
295 {
296     std::vector<DlpLinkFileInfo> linkList;
297     DlpLinkManager::GetInstance().DumpDlpLinkFile(linkList);
298     int listSize = static_cast<int>(linkList.size());
299     for (int i = 0; i < listSize; i++) {
300         params.entryName = linkList[i].dlpLinkName;
301         params.entryStat = &linkList[i].fileStat;
302         if (AddDirentry(params) != 0) {
303             fuse_reply_err(params.req, EINVAL);
304             return -1;
305         }
306     }
307     return 0;
308 }
309 
FuseDaemonReadDir(fuse_req_t req,fuse_ino_t ino,size_t size,off_t off,struct fuse_file_info * fi)310 static void FuseDaemonReadDir(fuse_req_t req, fuse_ino_t ino, size_t size, off_t off, struct fuse_file_info *fi)
311 {
312     (void)fi;
313     if (off < 0 || off > DLP_MAX_CONTENT_SIZE) {
314         fuse_reply_err(req, ENOTDIR);
315         return;
316     }
317 
318     if (ino != ROOT_INODE) {
319         fuse_reply_err(req, ENOTDIR);
320         return;
321     }
322     if (size > MAX_READ_DIR_BUF_SIZE) {
323         fuse_reply_err(req, EINVAL);
324         return;
325     }
326 
327     char* readBuf = reinterpret_cast<char*>(malloc(size));
328     if (readBuf == nullptr) {
329         fuse_reply_err(req, EFAULT);
330         return;
331     }
332     (void)memset_s(readBuf, size, 0, size);
333 
334     struct DirAddParams params;
335     params.req = req;
336     params.directBuf = readBuf;
337     params.bufLen = size;
338     params.nextOff = 0;
339 
340     if (AddRootDirentry(params) != 0) {
341         free(readBuf);
342         return;
343     }
344 
345     if (AddLinkFilesDirentry(params) != 0) {
346         free(readBuf);
347         return;
348     }
349 
350     if (params.curOff <= off) {
351         fuse_reply_buf(req, nullptr, 0);
352     } else {
353         fuse_reply_buf(req, readBuf + off, params.nextOff - off);
354     }
355     free(readBuf);
356 }
357 
FuseDaemonUpdateTime(fuse_req_t req,int toSet,DlpLinkFile * dlpLink)358 bool FuseDaemonUpdateTime(fuse_req_t req, int toSet, DlpLinkFile* dlpLink)
359 {
360     DLP_LOG_DEBUG(LABEL, "Set link file update time, type %{public}d", toSet);
361     bool isUpdateTime = false;
362     struct stat fileStat = dlpLink->GetFileStat();
363     if ((static_cast<uint32_t>(toSet) & FUSE_SET_ATTR_MTIME) != 0) {
364         UpdateCurrTimeStat(&fileStat.st_mtim);
365         isUpdateTime = true;
366     }
367     if ((static_cast<uint32_t>(toSet) & FUSE_SET_ATTR_CTIME) != 0) {
368         UpdateCurrTimeStat(&fileStat.st_ctim);
369         isUpdateTime = true;
370     }
371     if ((static_cast<uint32_t>(toSet) & FUSE_SET_ATTR_ATIME) != 0) {
372         UpdateCurrTimeStat(&fileStat.st_atim);
373         isUpdateTime = true;
374     }
375     if (isUpdateTime && (static_cast<uint32_t>(toSet) & FUSE_SET_ATTR_SIZE) == 0) {
376         fuse_reply_attr(req, &fileStat, DEFAULT_ATTR_TIMEOUT);
377         return false;
378     }
379     return true;
380 }
381 
FuseDaemonSetAttr(fuse_req_t req,fuse_ino_t ino,struct stat * attr,int toSet,struct fuse_file_info * fi)382 void FuseDaemonSetAttr(fuse_req_t req, fuse_ino_t ino, struct stat *attr, int toSet, struct fuse_file_info *fi)
383 {
384     (void)fi;
385     if (attr == nullptr) {
386         DLP_LOG_ERROR(LABEL, "Set link file attr fail, attr invalid");
387         fuse_reply_err(req, EINVAL);
388         return;
389     }
390 
391     if (ino == ROOT_INODE) {
392         DLP_LOG_ERROR(LABEL, "Set link file attr fail, cannot set attr on root inode");
393         fuse_reply_err(req, EACCES);
394         return;
395     }
396 
397     DlpLinkFile* dlpLink = GetFileNode(ino);
398     if (dlpLink == nullptr) {
399         DLP_LOG_ERROR(LABEL, "Set link file attr fail, wrong ino");
400         fuse_reply_err(req, ENOENT);
401         return;
402     }
403 
404     if (!FuseDaemonUpdateTime(req, toSet, dlpLink)) {
405         return;
406     }
407 
408     if ((static_cast<uint32_t>(toSet) & FUSE_SET_ATTR_SIZE) == 0) {
409         DLP_LOG_ERROR(LABEL, "Set link file attr fail, type %{public}d not support", toSet);
410         fuse_reply_err(req, EACCES);
411         return;
412     }
413 
414     if (attr->st_size < 0 || attr->st_size > DLP_MAX_CONTENT_SIZE) {
415         DLP_LOG_ERROR(LABEL, "Set link file attr fail, file size too large");
416         fuse_reply_err(req, EINVAL);
417         return;
418     }
419     int32_t ret = dlpLink->Truncate(static_cast<uint32_t>(attr->st_size));
420     if (ret != DLP_OK) {
421         DLP_LOG_ERROR(LABEL, "Set link file attr fail, errno is %{public}d", ret);
422         fuse_reply_err(req, EINVAL);
423         return;
424     }
425 
426     DLP_LOG_INFO(LABEL, "Set link file attr succ");
427     struct stat fileStat = dlpLink->GetLinkStat();
428     fuse_reply_attr(req, &fileStat, DEFAULT_ATTR_TIMEOUT);
429 }
430 
FuseDaemonInit(void * userdata,struct fuse_conn_info * conn)431 static void FuseDaemonInit(void *userdata, struct fuse_conn_info *conn)
432 {
433     (void)userdata;
434     if (conn == nullptr) {
435         DLP_LOG_ERROR(LABEL, "Fuse init, fuse conn info is null");
436         return;
437     }
438     conn->want |= FUSE_CAP_WRITEBACK_CACHE;
439 }
440 
441 struct fuse_lowlevel_ops FuseDaemon::fuseDaemonOper_ = {
442     .init = FuseDaemonInit,
443     .lookup = FuseDaemonLookup,
444     .forget = FuseDaemonForget,
445     .getattr = FuseDaemonGetattr,
446     .setattr = FuseDaemonSetAttr,
447     .open = FuseDaemonOpen,
448     .read = FuseDaemonRead,
449     .write = FuseDaemonWrite,
450     .readdir = FuseDaemonReadDir,
451 };
452 
GetRootFileStat()453 struct stat* FuseDaemon::GetRootFileStat()
454 {
455     return &FuseDaemon::rootFileStat_;
456 }
457 
InitRootFileStat(void)458 void FuseDaemon::InitRootFileStat(void)
459 {
460     (void)memset_s(&rootFileStat_, sizeof(rootFileStat_), 0, sizeof(rootFileStat_));
461     rootFileStat_.st_ino = ROOT_INODE;
462     rootFileStat_.st_mode = S_IFDIR | ROOT_INODE_ACCESS;
463     rootFileStat_.st_nlink = 1;
464     rootFileStat_.st_uid = getuid();
465     rootFileStat_.st_gid = getgid();
466     UpdateCurrTimeStat(&rootFileStat_.st_atim);
467     UpdateCurrTimeStat(&rootFileStat_.st_mtim);
468     UpdateCurrTimeStat(&rootFileStat_.st_ctim);
469 }
470 
NotifyDaemonEnable(void)471 void FuseDaemon::NotifyDaemonEnable(void)
472 {
473     std::unique_lock<std::mutex> lck(daemonEnableMtx_);
474     daemonStatus_ = DAEMON_ENABLE;
475     daemonEnableCv_.notify_all();
476 }
477 
NotifyDaemonDisable(void)478 void FuseDaemon::NotifyDaemonDisable(void)
479 {
480     std::unique_lock<std::mutex> lck(daemonEnableMtx_);
481     daemonStatus_ = DAEMON_DISABLE;
482     daemonEnableCv_.notify_all();
483 }
484 
WaitDaemonEnable(void)485 int FuseDaemon::WaitDaemonEnable(void)
486 {
487     DLP_LOG_INFO(LABEL, "Wait fuse fs daemon enable");
488     std::unique_lock<std::mutex> lck(daemonEnableMtx_);
489     if (daemonStatus_ == DAEMON_UNDEF) {
490         daemonEnableCv_.wait_for(lck, std::chrono::seconds(1));
491     }
492 
493     if (daemonStatus_ == DAEMON_ENABLE) {
494         DLP_LOG_INFO(LABEL, "Wait fuse fs daemon enable succ");
495         return 0;
496     }
497 
498     DLP_LOG_INFO(LABEL, "Wait fuse fs daemon enable fail, time out");
499     return -1;
500 }
501 
FuseFsDaemonThread(int fuseFd)502 void FuseDaemon::FuseFsDaemonThread(int fuseFd)
503 {
504     struct stat fileStat;
505     if (fstat(fuseFd, &fileStat) < 0) {
506         DLP_LOG_ERROR(LABEL, "Fuse fs daemon exit, %{public}d is wrong fd, errno %{public}d", fuseFd, errno);
507         NotifyDaemonDisable();
508         return;
509     }
510 
511     char mountPoint[MAX_FILE_NAME_LEN] = {0};
512     int ret = snprintf_s(mountPoint, sizeof(mountPoint), MAX_FILE_NAME_LEN, "/dev/fd/%d", fuseFd);
513     if (ret <= 0) {
514         DLP_LOG_ERROR(LABEL, "Fuse fs daemon exit, snprintf_s fail");
515         NotifyDaemonDisable();
516         return;
517     }
518 
519     struct fuse_args args = FUSE_ARGS_INIT(0, nullptr);
520     fuse_opt_add_arg(&args, mountPoint);
521 
522     struct fuse_session* se = fuse_session_new(&args, &fuseDaemonOper_, sizeof(fuseDaemonOper_), nullptr);
523     if (se == nullptr) {
524         DLP_LOG_ERROR(LABEL, "Fuse fs daemon exit, create fuse session fail");
525         NotifyDaemonDisable();
526         fuse_opt_free_args(&args);
527         return;
528     }
529 
530     if (fuse_session_mount(se, mountPoint) != 0) {
531         DLP_LOG_ERROR(LABEL, "Fuse fs daemon exit, mount fuse session fail");
532         NotifyDaemonDisable();
533         fuse_session_destroy(se);
534         fuse_opt_free_args(&args);
535         return;
536     }
537 
538     InitRootFileStat();
539     NotifyDaemonEnable();
540 
541     if (fuse_session_loop(se) != 0) {
542         DLP_LOG_ERROR(LABEL, "Fuse fs daemon exit, fuse session loop end");
543     }
544 
545     fuse_session_destroy(se);
546     fuse_opt_free_args(&args);
547 }
548 
InitFuseFs()549 int FuseDaemon::InitFuseFs()
550 {
551     if (init_) {
552         DLP_LOG_ERROR(LABEL, "Fuse fs has init already!");
553         return -1;
554     }
555     init_ = true;
556     int fuseDevFd = GetDlpFuseFd();
557     if (fuseDevFd < 0) {
558         DLP_LOG_ERROR(LABEL, "Init fuse fs fail: dev fd is error");
559         return -1;
560     }
561     daemonStatus_ = DAEMON_UNDEF;
562 
563     std::thread daemonThread([fuseDevFd] { FuseFsDaemonThread(fuseDevFd); });
564     pthread_setname_np(daemonThread.native_handle(), THREAD_OS_DLP_FUSE);
565     daemonThread.detach();
566     return WaitDaemonEnable();
567 }
568 }  // namespace DlpPermission
569 }  // namespace Security
570 }  // namespace OHOS
571