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