• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2021-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 "fault_logger_daemon.h"
17 
18 #include <algorithm>
19 #include <cerrno>
20 #include <csignal>
21 #include <cstring>
22 #include <ctime>
23 #include <dirent.h>
24 #include <fcntl.h>
25 #include <fstream>
26 #include <securec.h>
27 #include <sstream>
28 #include <unistd.h>
29 #include <vector>
30 
31 #include <sys/epoll.h>
32 #include <sys/socket.h>
33 #include <sys/stat.h>
34 #include <sys/syscall.h>
35 #include <sys/types.h>
36 #include <sys/un.h>
37 #include <sys/wait.h>
38 
39 #include "dfx_define.h"
40 #include "dfx_exception.h"
41 #include "dfx_log.h"
42 #include "dfx_util.h"
43 #include "directory_ex.h"
44 #include "fault_logger_config.h"
45 #include "fault_logger_pipe.h"
46 #include "faultloggerd_socket.h"
47 #ifndef HISYSEVENT_DISABLE
48 #include "hisysevent.h"
49 #endif
50 
51 namespace OHOS {
52 namespace HiviewDFX {
53 std::shared_ptr<FaultLoggerConfig> faultLoggerConfig_;
54 std::shared_ptr<FaultLoggerPipeMap> faultLoggerPipeMap_;
55 
56 namespace {
57 constexpr int32_t MAX_CONNECTION = 30;
58 constexpr int32_t REQUEST_BUF_SIZE = 2048;
59 constexpr int32_t MAX_EPOLL_EVENT = 1024;
60 const int32_t FAULTLOG_FILE_PROP = 0640;
61 
62 static constexpr uint32_t ROOT_UID = 0;
63 static constexpr uint32_t BMS_UID = 1000;
64 static constexpr uint32_t HIVIEW_UID = 1201;
65 static constexpr uint32_t HIDUMPER_SERVICE_UID = 1212;
66 static constexpr uint32_t FOUNDATION_UID = 5523;
67 static const std::string FAULTLOGGERD_TAG = "FaultLoggerd";
68 static const std::string DAEMON_RESP = "RESP:COMPLETE";
69 static const int DAEMON_REMOVE_FILE_TIME_S = 60;
70 
GetRequestTypeName(int32_t type)71 static std::string GetRequestTypeName(int32_t type)
72 {
73     switch (type) {
74         case (int32_t)FaultLoggerType::CPP_CRASH:
75             return "cppcrash";
76         case (int32_t)FaultLoggerType::CPP_STACKTRACE: // change the name to nativestack ?
77             return "stacktrace";
78         case (int32_t)FaultLoggerType::JS_STACKTRACE:
79             return "jsstack";
80         case (int32_t)FaultLoggerType::JS_HEAP_SNAPSHOT:
81             return "jsheap";
82         case (int32_t)FaultLoggerType::LEAK_STACKTRACE:
83             return "leakstack";
84         case (int32_t)FaultLoggerType::FFRT_CRASH_LOG:
85             return "ffrtlog";
86         default:
87             return "unsupported";
88     }
89 }
90 
CheckCallerUID(uint32_t callerUid)91 static bool CheckCallerUID(uint32_t callerUid)
92 {
93     // If caller's is BMS / root or caller's uid/pid is validate, just return true
94     if ((callerUid == BMS_UID) ||
95         (callerUid == ROOT_UID) ||
96         (callerUid == HIVIEW_UID) ||
97         (callerUid == HIDUMPER_SERVICE_UID) ||
98         (callerUid == FOUNDATION_UID)) {
99         return true;
100     }
101     DFXLOG_WARN("%s :: CheckCallerUID :: Caller Uid(%d) is unexpectly.\n", FAULTLOGGERD_TAG.c_str(), callerUid);
102     return false;
103 }
104 }
105 
ReportExceptionToSysEvent(CrashDumpException & exception)106 static void ReportExceptionToSysEvent(CrashDumpException& exception)
107 {
108 #ifndef HISYSEVENT_DISABLE
109     std::string errMessage;
110     if (exception.error == CRASH_DUMP_LOCAL_REPORT) {
111         std::ifstream rfile;
112         if (strlen(exception.message) == 0) {
113             return;
114         }
115         rfile.open(exception.message, std::ios::binary | std::ios::ate);
116         if (!rfile.is_open()) {
117             return;
118         }
119         std::streamsize size = rfile.tellg();
120         rfile.seekg(0, std::ios::beg);
121         std::vector<char> buf(size);
122         rfile.read(buf.data(), size);
123         errMessage = std::string(buf.begin(), buf.end());
124     } else {
125         errMessage = exception.message;
126     }
127     HiSysEventWrite(
128         HiSysEvent::Domain::RELIABILITY,
129         "CPP_CRASH_EXCEPTION",
130         HiSysEvent::EventType::FAULT,
131         "PID", exception.pid,
132         "UID", exception.uid,
133         "HAPPEN_TIME", exception.time,
134         "ERROR_CODE", exception.error,
135         "ERROR_MSG", errMessage);
136 #endif
137 }
138 
FaultLoggerDaemon()139 FaultLoggerDaemon::FaultLoggerDaemon()
140 {
141 }
142 
StartServer()143 int32_t FaultLoggerDaemon::StartServer()
144 {
145     if (!CreateSockets()) {
146         DFXLOG_ERROR("%s :: Failed to create faultloggerd sockets.", FAULTLOGGERD_TAG.c_str());
147         CleanupSockets();
148         return -1;
149     }
150 
151     if (!InitEnvironment()) {
152         DFXLOG_ERROR("%s :: Failed to init environment.", FAULTLOGGERD_TAG.c_str());
153         CleanupSockets();
154         return -1;
155     }
156 
157     if (!CreateEventFd()) {
158         DFXLOG_ERROR("%s :: Failed to create eventFd.", FAULTLOGGERD_TAG.c_str());
159         CleanupSockets();
160         return -1;
161     }
162 
163     // loop in WaitForRequest
164     WaitForRequest();
165 
166     CleanupEventFd();
167     CleanupSockets();
168     return 0;
169 }
170 
HandleAccept(int32_t epollFd,int32_t socketFd)171 void FaultLoggerDaemon::HandleAccept(int32_t epollFd, int32_t socketFd)
172 {
173     struct sockaddr_un clientAddr;
174     socklen_t clientAddrSize = static_cast<socklen_t>(sizeof(clientAddr));
175 
176     int connectionFd = accept(socketFd, reinterpret_cast<struct sockaddr *>(&clientAddr), &clientAddrSize);
177     if (connectionFd < 0) {
178         DFXLOG_WARN("%s :: Failed to accept connection", FAULTLOGGERD_TAG.c_str());
179         return;
180     }
181 
182     AddEvent(eventFd_, connectionFd, EPOLLIN);
183     connectionMap_[connectionFd] = socketFd;
184 }
185 
186 #ifdef FAULTLOGGERD_FUZZER
HandleRequestForFuzzer(int32_t epollFd,int32_t connectionFd)187 void FaultLoggerDaemon::HandleRequestForFuzzer(int32_t epollFd, int32_t connectionFd)
188 {
189     HandleRequest(epollFd, connectionFd);
190 }
191 #endif
192 
CheckReadRequest(ssize_t nread,ssize_t size)193 static bool CheckReadRequest(ssize_t nread, ssize_t size)
194 {
195     if (nread < 0) {
196         DFXLOG_ERROR("%s :: Failed to read message", FAULTLOGGERD_TAG.c_str());
197         return false;
198     } else if (nread == 0) {
199         DFXLOG_ERROR("%s :: Read null from request socket", FAULTLOGGERD_TAG.c_str());
200         return false;
201     } else if (nread != static_cast<long>(size)) {
202         return false;
203     }
204     return true;
205 }
206 
HandleRequest(int32_t epollFd,int32_t connectionFd)207 void FaultLoggerDaemon::HandleRequest(int32_t epollFd, int32_t connectionFd)
208 {
209     if (epollFd < 0 || connectionFd < 3) { // 3: not allow fd = 0,1,2 because they are reserved by system
210         DFXLOG_ERROR("%s :: HandleRequest recieved invalid fd parmeters.", FAULTLOGGERD_TAG.c_str());
211         return;
212     }
213 
214     std::vector<uint8_t> buf(REQUEST_BUF_SIZE, 0);
215     do {
216         ssize_t nread = read(connectionFd, buf.data(), REQUEST_BUF_SIZE);
217         if (CheckReadRequest(nread, sizeof(FaultLoggerdStatsRequest))) {
218             HandleDumpStats(connectionFd, reinterpret_cast<FaultLoggerdStatsRequest *>(buf.data()));
219             break;
220         }
221 
222         if (!CheckReadRequest(nread, sizeof(FaultLoggerdRequest))) {
223             break;
224         }
225 
226         auto request = reinterpret_cast<FaultLoggerdRequest *>(buf.data());
227         if (!CheckRequestCredential(connectionFd, request)) {
228             break;
229         }
230 
231         DFXLOG_DEBUG("%s :: clientType(%d).\n", FAULTLOGGERD_TAG.c_str(), request->clientType);
232         switch (request->clientType) {
233             case static_cast<int32_t>(FaultLoggerClientType::DEFAULT_CLIENT):
234                 HandleDefaultClientRequest(connectionFd, request);
235                 break;
236             case static_cast<int32_t>(FaultLoggerClientType::LOG_FILE_DES_CLIENT):
237                 HandleLogFileDesClientRequest(connectionFd, request);
238                 break;
239             case static_cast<int32_t>(FaultLoggerClientType::PRINT_T_HILOG_CLIENT):
240                 HandlePrintTHilogClientRequest(connectionFd, request);
241                 break;
242             case static_cast<int32_t>(FaultLoggerClientType::PERMISSION_CLIENT):
243                 HandlePermissionRequest(connectionFd, request);
244                 break;
245             case static_cast<int32_t>(FaultLoggerClientType::SDK_DUMP_CLIENT):
246                 HandleSdkDumpRequest(connectionFd, request);
247                 break;
248             case static_cast<int32_t>(FaultLoggerClientType::PIPE_FD_CLIENT):
249                 HandlePipeFdClientRequest(connectionFd, request);
250                 break;
251             case static_cast<int32_t>(FaultLoggerClientType::REPORT_EXCEPTION_CLIENT):
252                 HandleExceptionRequest(connectionFd, request);
253                 break;
254             default:
255                 DFXLOG_ERROR("%s :: unknown clientType(%d).\n", FAULTLOGGERD_TAG.c_str(), request->clientType);
256                 break;
257         }
258     } while (false);
259     DelEvent(eventFd_, connectionFd, EPOLLIN);
260     connectionMap_.erase(connectionFd);
261 }
262 
InitEnvironment()263 bool FaultLoggerDaemon::InitEnvironment()
264 {
265     faultLoggerConfig_ = std::make_shared<FaultLoggerConfig>(LOG_FILE_NUMBER, LOG_FILE_SIZE,
266         LOG_FILE_PATH, DEBUG_LOG_FILE_PATH);
267     faultLoggerPipeMap_ = std::make_shared<FaultLoggerPipeMap>();
268 
269     if (!OHOS::ForceCreateDirectory(faultLoggerConfig_->GetLogFilePath())) {
270         DFXLOG_ERROR("%s :: Failed to ForceCreateDirectory GetLogFilePath", FAULTLOGGERD_TAG.c_str());
271         return false;
272     }
273 
274     if (!OHOS::ForceCreateDirectory(faultLoggerConfig_->GetDebugLogFilePath())) {
275         DFXLOG_ERROR("%s :: Failed to ForceCreateDirectory GetDebugLogFilePath", FAULTLOGGERD_TAG.c_str());
276         return false;
277     }
278 
279     signal(SIGCHLD, SIG_IGN);
280     signal(SIGPIPE, SIG_IGN);
281     return true;
282 }
283 
HandleDefaultClientRequest(int32_t connectionFd,const FaultLoggerdRequest * request)284 void FaultLoggerDaemon::HandleDefaultClientRequest(int32_t connectionFd, const FaultLoggerdRequest * request)
285 {
286     RemoveTempFileIfNeed();
287 
288     int fd = CreateFileForRequest(request->type, request->pid, request->tid, request->time, false);
289     if (fd < 0) {
290         DFXLOG_ERROR("%s :: Failed to create log file, errno(%d)", FAULTLOGGERD_TAG.c_str(), errno);
291         return;
292     }
293     RecordFileCreation(request->type, request->pid);
294     SendFileDescriptorToSocket(connectionFd, fd);
295 
296     close(fd);
297 }
298 
HandleLogFileDesClientRequest(int32_t connectionFd,const FaultLoggerdRequest * request)299 void FaultLoggerDaemon::HandleLogFileDesClientRequest(int32_t connectionFd, const FaultLoggerdRequest * request)
300 {
301     int fd = CreateFileForRequest(request->type, request->pid, request->tid, request->time, true);
302     if (fd < 0) {
303         DFXLOG_ERROR("%s :: Failed to create log file, errno(%d)", FAULTLOGGERD_TAG.c_str(), errno);
304         return;
305     }
306     SendFileDescriptorToSocket(connectionFd, fd);
307 
308     close(fd);
309 }
310 
HandleExceptionRequest(int32_t connectionFd,FaultLoggerdRequest * request)311 void FaultLoggerDaemon::HandleExceptionRequest(int32_t connectionFd, FaultLoggerdRequest * request)
312 {
313     if (write(connectionFd, DAEMON_RESP.c_str(), DAEMON_RESP.length()) != static_cast<ssize_t>(DAEMON_RESP.length())) {
314         DFXLOG_ERROR("%s :: Failed to write DAEMON_RESP.", FAULTLOGGERD_TAG.c_str());
315     }
316 
317     CrashDumpException exception;
318     (void)memset_s(&exception, sizeof(CrashDumpException), 0, sizeof(CrashDumpException));
319     ssize_t nread = read(connectionFd, &exception, sizeof(CrashDumpException));
320     if (!CheckReadRequest(nread, sizeof(CrashDumpException))) {
321         return;
322     }
323 
324     ReportExceptionToSysEvent(exception);
325 }
326 
HandlePipeFdClientRequest(int32_t connectionFd,FaultLoggerdRequest * request)327 void FaultLoggerDaemon::HandlePipeFdClientRequest(int32_t connectionFd, FaultLoggerdRequest * request)
328 {
329     DFXLOG_DEBUG("%s :: pid(%d), pipeType(%d).\n", FAULTLOGGERD_TAG.c_str(), request->pid, request->pipeType);
330     int fd = -1;
331     FaultLoggerPipe2* faultLoggerPipe = faultLoggerPipeMap_->Get(request->pid);
332     if (faultLoggerPipe == nullptr) {
333         DFXLOG_ERROR("%s :: cannot find pipe fd for pid(%d).\n", FAULTLOGGERD_TAG.c_str(), request->pid);
334         return;
335     }
336     switch (request->pipeType) {
337         case (int32_t)FaultLoggerPipeType::PIPE_FD_READ_BUF: {
338             FaultLoggerCheckPermissionResp resSecurityCheck = SecurityCheck(connectionFd, request);
339             if (FaultLoggerCheckPermissionResp::CHECK_PERMISSION_PASS != resSecurityCheck) {
340                 return;
341             }
342             if ((faultLoggerPipe->faultLoggerPipeBuf_) != nullptr) {
343                 fd = faultLoggerPipe->faultLoggerPipeBuf_->GetReadFd();
344             }
345             break;
346         }
347         case (int32_t)FaultLoggerPipeType::PIPE_FD_WRITE_BUF: {
348             if ((faultLoggerPipe->faultLoggerPipeBuf_) != nullptr) {
349                 fd = faultLoggerPipe->faultLoggerPipeBuf_->GetWriteFd();
350             }
351             break;
352         }
353         case (int32_t)FaultLoggerPipeType::PIPE_FD_READ_RES: {
354             FaultLoggerCheckPermissionResp resSecurityCheck = SecurityCheck(connectionFd, request);
355             if (FaultLoggerCheckPermissionResp::CHECK_PERMISSION_PASS != resSecurityCheck) {
356                 return;
357             }
358             if ((faultLoggerPipe->faultLoggerPipeRes_) != nullptr) {
359                 fd = faultLoggerPipe->faultLoggerPipeRes_->GetReadFd();
360             }
361             break;
362         }
363         case (int32_t)FaultLoggerPipeType::PIPE_FD_WRITE_RES: {
364             if ((faultLoggerPipe->faultLoggerPipeRes_) != nullptr) {
365                 fd = faultLoggerPipe->faultLoggerPipeRes_->GetWriteFd();
366             }
367             break;
368         }
369         case (int32_t)FaultLoggerPipeType::PIPE_FD_DELETE: {
370             faultLoggerPipeMap_->Del(request->pid);
371             return;
372         }
373         case (int32_t)FaultLoggerPipeType::PIPE_FD_JSON_READ_BUF: {
374             FaultLoggerCheckPermissionResp resSecurityCheck = SecurityCheck(connectionFd, request);
375             if (FaultLoggerCheckPermissionResp::CHECK_PERMISSION_PASS != resSecurityCheck) {
376                 return;
377             }
378             if ((faultLoggerPipe->faultLoggerJsonPipeBuf_) != nullptr) {
379                 fd = faultLoggerPipe->faultLoggerJsonPipeBuf_->GetReadFd();
380             }
381             break;
382         }
383         case (int32_t)FaultLoggerPipeType::PIPE_FD_JSON_WRITE_BUF: {
384             if ((faultLoggerPipe->faultLoggerJsonPipeBuf_) != nullptr) {
385                 fd = faultLoggerPipe->faultLoggerJsonPipeBuf_->GetWriteFd();
386             }
387             break;
388         }
389         case (int32_t)FaultLoggerPipeType::PIPE_FD_JSON_READ_RES: {
390             FaultLoggerCheckPermissionResp resSecurityCheck = SecurityCheck(connectionFd, request);
391             if (FaultLoggerCheckPermissionResp::CHECK_PERMISSION_PASS != resSecurityCheck) {
392                 return;
393             }
394             if ((faultLoggerPipe->faultLoggerJsonPipeRes_) != nullptr) {
395                 fd = faultLoggerPipe->faultLoggerJsonPipeRes_->GetReadFd();
396             }
397             break;
398         }
399         case (int32_t)FaultLoggerPipeType::PIPE_FD_JSON_WRITE_RES: {
400             if ((faultLoggerPipe->faultLoggerJsonPipeRes_) != nullptr) {
401                 fd = faultLoggerPipe->faultLoggerJsonPipeRes_->GetWriteFd();
402             }
403             break;
404         }
405         default:
406             DFXLOG_ERROR("%s :: unknown pipeType(%d).", FAULTLOGGERD_TAG.c_str(), request->pipeType);
407             return;
408     }
409     if (fd < 0) {
410         DFXLOG_ERROR("%s :: Failed to get pipe fd, pipeType(%d)", FAULTLOGGERD_TAG.c_str(), request->pipeType);
411         return;
412     }
413     SendFileDescriptorToSocket(connectionFd, fd);
414 }
415 
HandlePrintTHilogClientRequest(int32_t const connectionFd,FaultLoggerdRequest * request)416 void FaultLoggerDaemon::HandlePrintTHilogClientRequest(int32_t const connectionFd, FaultLoggerdRequest * request)
417 {
418     char buf[LINE_BUF_SIZE] = {0};
419 
420     if (write(connectionFd, DAEMON_RESP.c_str(), DAEMON_RESP.length()) != static_cast<ssize_t>(DAEMON_RESP.length())) {
421         DFXLOG_ERROR("%s :: Failed to write DAEMON_RESP.", FAULTLOGGERD_TAG.c_str());
422     }
423 
424     int nread = read(connectionFd, buf, sizeof(buf) - 1);
425     if (nread < 0) {
426         DFXLOG_ERROR("%s :: Failed to read message, errno(%d)", FAULTLOGGERD_TAG.c_str(), errno);
427     } else if (nread == 0) {
428         DFXLOG_ERROR("%s :: HandlePrintTHilogClientRequest :: Read null from request socket", FAULTLOGGERD_TAG.c_str());
429     } else {
430         DFXLOG_ERROR("%s", buf);
431     }
432 }
433 
SecurityCheck(int32_t connectionFd,FaultLoggerdRequest * request)434 FaultLoggerCheckPermissionResp FaultLoggerDaemon::SecurityCheck(int32_t connectionFd, FaultLoggerdRequest * request)
435 {
436     FaultLoggerCheckPermissionResp resCheckPermission = FaultLoggerCheckPermissionResp::CHECK_PERMISSION_REJECT;
437 
438     struct ucred rcred;
439     do {
440         int optval = 1;
441         if (setsockopt(connectionFd, SOL_SOCKET, SO_PASSCRED, &optval, sizeof(optval)) == -1) {
442             DFXLOG_ERROR("%s :: setsockopt SO_PASSCRED error, errno(%d)", FAULTLOGGERD_TAG.c_str(), errno);
443             break;
444         }
445 
446         if (write(connectionFd, DAEMON_RESP.c_str(), DAEMON_RESP.length()) !=
447             static_cast<ssize_t>(DAEMON_RESP.length())) {
448             DFXLOG_ERROR("%s :: Failed to write DAEMON_RESP, errno(%d)", FAULTLOGGERD_TAG.c_str(), errno);
449         }
450 
451         if (!RecvMsgCredFromSocket(connectionFd, &rcred)) {
452             DFXLOG_ERROR("%s :: Recv msg ucred error.", FAULTLOGGERD_TAG.c_str());
453             break;
454         }
455 
456         request->uid = rcred.uid;
457         request->callerPid = static_cast<int32_t>(rcred.pid);
458 
459         auto it = connectionMap_.find(connectionFd);
460         if (it == connectionMap_.end()) {
461             break;
462         }
463 
464         if (it->second == sdkdumpSocketFd_) {
465             resCheckPermission = FaultLoggerCheckPermissionResp::CHECK_PERMISSION_PASS;
466             break;
467         }
468 
469         bool res = CheckCallerUID(request->uid);
470         if (res) {
471             resCheckPermission = FaultLoggerCheckPermissionResp::CHECK_PERMISSION_PASS;
472         }
473     } while (false);
474 
475     return resCheckPermission;
476 }
477 
HandlePermissionRequest(int32_t connectionFd,FaultLoggerdRequest * request)478 void FaultLoggerDaemon::HandlePermissionRequest(int32_t connectionFd, FaultLoggerdRequest * request)
479 {
480     FaultLoggerCheckPermissionResp resSecurityCheck = SecurityCheck(connectionFd, request);
481     if (FaultLoggerCheckPermissionResp::CHECK_PERMISSION_PASS == resSecurityCheck) {
482         send(connectionFd, "1", strlen("1"), 0);
483     }
484     if (FaultLoggerCheckPermissionResp::CHECK_PERMISSION_REJECT == resSecurityCheck) {
485         send(connectionFd, "2", strlen("2"), 0);
486     }
487 }
488 
HandleSdkDumpRequest(int32_t connectionFd,FaultLoggerdRequest * request)489 void FaultLoggerDaemon::HandleSdkDumpRequest(int32_t connectionFd, FaultLoggerdRequest * request)
490 {
491     DFXLOG_INFO("Receive dump request for pid:%d tid:%d.", request->pid, request->tid);
492     FaultLoggerSdkDumpResp resSdkDump = FaultLoggerSdkDumpResp::SDK_DUMP_PASS;
493     FaultLoggerCheckPermissionResp resSecurityCheck = SecurityCheck(connectionFd, request);
494 
495     /*
496     *           all     threads my user, local pid             my user, remote pid     other user's process
497     * 3rd       Y       Y(in signal_handler local)     Y(in signal_handler loacl)      N
498     * system    Y       Y(in signal_handler local)     Y(in signal_handler loacl)      Y(in signal_handler remote)
499     * root      Y       Y(in signal_handler local)     Y(in signal_handler loacl)      Y(in signal_handler remote)
500     */
501 
502     /*
503     * 1. pid != 0 && tid != 0:    means we want dump a thread, so we send signal to a thread.
504         Main thread stack is tid's stack, we need ignore other thread info.
505     * 2. pid != 0 && tid == 0:    means we want dump a process, so we send signal to process.
506         Main thead stack is pid's stack, we need other tread info.
507     */
508 
509     /*
510      * in signal_handler we need to check caller pid and tid(which is send to signal handler by SYS_rt_sig.).
511      * 1. caller pid == signal pid, means we do back trace in ourself process, means local backtrace.
512      *      |- we do all tid back trace in signal handler's local unwind.
513      * 2. pid != signal pid, means we do remote back trace.
514      */
515 
516     /*
517      * in local back trace, all unwind stack will save to signal_handler global var.(mutex lock in signal handler.)
518      * in remote back trace, all unwind stack will save to file, and read in dump_catcher, then return.
519      */
520 
521     do {
522         if ((request->pid <= 0) || (FaultLoggerCheckPermissionResp::CHECK_PERMISSION_REJECT == resSecurityCheck)) {
523             DFXLOG_ERROR("%s :: HandleSdkDumpRequest :: pid(%d) or resSecurityCheck(%d) fail.\n", \
524                 FAULTLOGGERD_TAG.c_str(), request->pid, (int)resSecurityCheck);
525             resSdkDump = FaultLoggerSdkDumpResp::SDK_DUMP_REJECT;
526             break;
527         }
528         if (IsCrashed(request->pid)) {
529             resSdkDump = FaultLoggerSdkDumpResp::SDK_PROCESS_CRASHED;
530             DFXLOG_WARN("%s :: pid(%d) has been crashed, break.\n", FAULTLOGGERD_TAG.c_str(), request->pid);
531             break;
532         }
533         if (faultLoggerPipeMap_->Check(request->pid, request->time)) {
534             resSdkDump = FaultLoggerSdkDumpResp::SDK_DUMP_REPEAT;
535             DFXLOG_ERROR("%s :: pid(%d) is dumping, break.\n", FAULTLOGGERD_TAG.c_str(), request->pid);
536             break;
537         }
538         faultLoggerPipeMap_->Set(request->pid, request->time, request->isJson);
539 
540 #pragma clang diagnostic push
541 #pragma clang diagnostic ignored "-Winitializer-overrides"
542         // defined in out/hi3516dv300/obj/third_party/musl/intermidiates/linux/musl_src_ported/include/signal.h
543         siginfo_t si {0};
544         si.si_signo = SIGDUMP;
545         si.si_errno = 0;
546         si.si_value.sival_int = request->tid;
547         si.si_code = request->sigCode;
548         si.si_pid = request->callerPid;
549         si.si_uid = static_cast<uid_t>(request->callerTid);
550 #pragma clang diagnostic pop
551         int32_t reqTid = 0;
552         if (request->tid == 0) {
553             /*
554              * means we need dump all the threads in a process
555              * --------
556              * Accroding to the linux manual, A process-directed signal may be delivered to any one of the
557              * threads that does not currently have the signal blocked. So we should specify the main thread
558              * as the target thread of signal.
559             */
560             reqTid = request->pid;
561         } else {
562             // means we need dump a specified thread
563             reqTid = request->tid;
564         }
565         if (syscall(SYS_rt_tgsigqueueinfo, request->pid, reqTid, si.si_signo, &si) != 0) {
566             DFXLOG_ERROR("Failed to SYS_rt_tgsigqueueinfo signal(%d), errno(%d).", si.si_signo, errno);
567             resSdkDump = FaultLoggerSdkDumpResp::SDK_DUMP_NOPROC;
568             break;
569         }
570     } while (false);
571     auto retMsg = std::to_string(resSdkDump);
572     send(connectionFd, retMsg.data(), retMsg.length(), 0);
573 }
574 
RecordFileCreation(int32_t type,int32_t pid)575 void FaultLoggerDaemon::RecordFileCreation(int32_t type, int32_t pid)
576 {
577     if (type == static_cast<int32_t>(FaultLoggerType::CPP_CRASH)) {
578         ClearTimeOutRecords();
579         crashTimeMap_[pid] = time(nullptr);
580     }
581 }
582 
ClearTimeOutRecords()583 void FaultLoggerDaemon::ClearTimeOutRecords()
584 {
585     constexpr int validTime = 8;
586     auto currentTime = time(nullptr);
587     for (auto it = crashTimeMap_.begin(); it != crashTimeMap_.end();) {
588         if ((it->second + validTime) <= currentTime) {
589             crashTimeMap_.erase(it++);
590         } else {
591             it++;
592         }
593     }
594 }
595 
IsCrashed(int32_t pid)596 bool FaultLoggerDaemon::IsCrashed(int32_t pid)
597 {
598     ClearTimeOutRecords();
599     return crashTimeMap_.find(pid) != crashTimeMap_.end();
600 }
601 
CreateFileForRequest(int32_t type,int32_t pid,int32_t tid,uint64_t time,bool debugFlag) const602 int32_t FaultLoggerDaemon::CreateFileForRequest(int32_t type, int32_t pid, int32_t tid,
603     uint64_t time, bool debugFlag) const
604 {
605     std::string typeStr = GetRequestTypeName(type);
606     if (typeStr == "unsupported") {
607         DFXLOG_ERROR("Unsupported request type(%d)", type);
608         return -1;
609     }
610 
611     std::string folderPath = "";
612     if (debugFlag == false) {
613         folderPath = faultLoggerConfig_->GetLogFilePath();
614     } else {
615         folderPath = faultLoggerConfig_->GetDebugLogFilePath();
616     }
617 
618     if (time == 0) {
619         time = static_cast<uint64_t>(std::chrono::duration_cast<std::chrono::milliseconds>\
620             (std::chrono::system_clock::now().time_since_epoch()).count());
621     }
622 
623     std::stringstream ss;
624     ss << folderPath << "/" << typeStr << "-" << pid;
625     if (type == FaultLoggerType::JS_HEAP_SNAPSHOT) {
626         ss << "-" << tid;
627     }
628     ss << "-" << time;
629     const std::string path = ss.str();
630     DFXLOG_INFO("%s :: file path(%s).\n", FAULTLOGGERD_TAG.c_str(), path.c_str());
631     if (!VerifyFilePath(path, VALID_FILE_PATH)) {
632         DFXLOG_ERROR("%s :: Open %s fail, please check it under valid path.\n", FAULTLOGGERD_TAG.c_str(), path.c_str());
633         return -1;
634     }
635     int32_t fd = OHOS_TEMP_FAILURE_RETRY(open(path.c_str(), O_RDWR | O_CREAT, FAULTLOG_FILE_PROP));
636     if (fd != -1) {
637         if (!ChangeModeFile(path, FAULTLOG_FILE_PROP)) {
638             DFXLOG_ERROR("%s :: Failed to ChangeMode CreateFileForRequest", FAULTLOGGERD_TAG.c_str());
639         }
640     }
641     return fd;
642 }
643 
RemoveTempFileIfNeed()644 void FaultLoggerDaemon::RemoveTempFileIfNeed()
645 {
646     int maxFileCount = 50;
647     int currentLogCounts = 0;
648 
649     std::vector<std::string> files;
650     OHOS::GetDirFiles(faultLoggerConfig_->GetLogFilePath(), files);
651     currentLogCounts = (int)files.size();
652 
653     maxFileCount = faultLoggerConfig_->GetLogFileMaxNumber();
654     if (currentLogCounts < maxFileCount) {
655         return;
656     }
657 
658     std::sort(files.begin(), files.end(),
659         [](const std::string& lhs, const std::string& rhs) -> int {
660         auto lhsSplitPos = lhs.find_last_of("-");
661         auto rhsSplitPos = rhs.find_last_of("-");
662         if (lhsSplitPos == std::string::npos || rhsSplitPos == std::string::npos) {
663             return lhs.compare(rhs) > 0;
664         }
665 
666         return lhs.substr(lhsSplitPos).compare(rhs.substr(rhsSplitPos)) > 0;
667     });
668 
669     time_t currentTime = static_cast<time_t>(time(nullptr));
670     if (currentTime <= 0) {
671         DFXLOG_ERROR("%s :: currentTime is less than zero CreateFileForRequest", FAULTLOGGERD_TAG.c_str());
672     }
673 
674     constexpr int deleteNum = 1;
675     int startIndex = maxFileCount > deleteNum ? maxFileCount - deleteNum : maxFileCount;
676     for (unsigned int index = (unsigned int)startIndex; index < files.size(); index++) {
677         struct stat st;
678         int err = stat(files[index].c_str(), &st);
679         if (err != 0) {
680             DFXLOG_ERROR("%s :: Get log stat failed, errno(%d).", FAULTLOGGERD_TAG.c_str(), errno);
681         } else {
682             if ((currentTime - st.st_mtime) <= DAEMON_REMOVE_FILE_TIME_S) {
683                 continue;
684             }
685         }
686 
687         OHOS::RemoveFile(files[index]);
688         DFXLOG_DEBUG("%s :: Now we rm file(%s) as max log number exceeded.", \
689             FAULTLOGGERD_TAG.c_str(), files[index].c_str());
690     }
691 }
692 
AddEvent(int32_t epollFd,int32_t addFd,uint32_t event)693 void FaultLoggerDaemon::AddEvent(int32_t epollFd, int32_t addFd, uint32_t event)
694 {
695     epoll_event ev;
696     ev.events = event;
697     ev.data.fd = addFd;
698     int ret = epoll_ctl(epollFd, EPOLL_CTL_ADD, addFd, &ev);
699     if (ret < 0) {
700         DFXLOG_WARN("%s :: Failed to epoll ctl add Fd(%d), errno(%d)", FAULTLOGGERD_TAG.c_str(), addFd, errno);
701     }
702 }
703 
DelEvent(int32_t epollFd,int32_t delFd,uint32_t event)704 void FaultLoggerDaemon::DelEvent(int32_t epollFd, int32_t delFd, uint32_t event)
705 {
706     epoll_event ev;
707     ev.events = event;
708     ev.data.fd = delFd;
709     int ret = epoll_ctl(epollFd, EPOLL_CTL_DEL, delFd, &ev);
710     if (ret < 0) {
711         DFXLOG_WARN("%s :: Failed to epoll ctl del Fd(%d), errno(%d)", FAULTLOGGERD_TAG.c_str(), delFd, errno);
712     }
713     close(delFd);
714 }
715 
CheckRequestCredential(int32_t connectionFd,FaultLoggerdRequest * request)716 bool FaultLoggerDaemon::CheckRequestCredential(int32_t connectionFd, FaultLoggerdRequest* request)
717 {
718     if (request == nullptr) {
719         return false;
720     }
721 
722     auto it = connectionMap_.find(connectionFd);
723     if (it == connectionMap_.end()) {
724         DFXLOG_ERROR("%s : Failed to find fd:%d, map size:%zu", FAULTLOGGERD_TAG.c_str(),
725             connectionFd, connectionMap_.size());
726         return false;
727     }
728 
729     if (it->second == crashSocketFd_ || it->second == sdkdumpSocketFd_) {
730         // only processdump use this socket
731         return true;
732     }
733 
734     struct ucred creds = {};
735     socklen_t credSize = sizeof(creds);
736     int err = getsockopt(connectionFd, SOL_SOCKET, SO_PEERCRED, &creds, &credSize);
737     if (err != 0) {
738         DFXLOG_ERROR("%s :: Failed to CheckRequestCredential, errno(%d)", FAULTLOGGERD_TAG.c_str(), errno);
739         return false;
740     }
741 
742     if (CheckCallerUID(creds.uid)) {
743         return true;
744     }
745 
746     bool isCredentialMatched = (creds.pid == request->pid);
747     if (request->clientType == (int32_t)REPORT_EXCEPTION_CLIENT) {
748         isCredentialMatched = (creds.uid == request->uid);   /* check uid when report exception */
749     }
750     if (!isCredentialMatched) {
751         DFXLOG_WARN("Failed to check request credential request:%d:%d cred:%d:%d fd:%d:%d",
752             request->pid, request->uid, creds.pid, creds.uid, it->second, crashSocketFd_);
753     }
754     return isCredentialMatched;
755 }
756 
CreateSockets()757 bool FaultLoggerDaemon::CreateSockets()
758 {
759     if (!StartListen(defaultSocketFd_, SERVER_SOCKET_NAME, MAX_CONNECTION)) {
760         return false;
761     }
762 
763     if (!StartListen(crashSocketFd_, SERVER_CRASH_SOCKET_NAME, MAX_CONNECTION)) {
764         close(defaultSocketFd_);
765         defaultSocketFd_ = -1;
766         return false;
767     }
768 
769     if (!StartListen(sdkdumpSocketFd_, SERVER_SDKDUMP_SOCKET_NAME, MAX_CONNECTION)) {
770         close(defaultSocketFd_);
771         defaultSocketFd_ = -1;
772         close(crashSocketFd_);
773         crashSocketFd_ = -1;
774         return false;
775     }
776 
777     return true;
778 }
779 
CleanupSockets()780 void FaultLoggerDaemon::CleanupSockets()
781 {
782     if (defaultSocketFd_ >= 0) {
783         close(defaultSocketFd_);
784         defaultSocketFd_ = -1;
785     }
786 
787     if (crashSocketFd_ >= 0) {
788         close(crashSocketFd_);
789         crashSocketFd_ = -1;
790     }
791 
792     if (sdkdumpSocketFd_ >= 0) {
793         close(sdkdumpSocketFd_);
794         sdkdumpSocketFd_ = -1;
795     }
796 }
797 
CreateEventFd()798 bool FaultLoggerDaemon::CreateEventFd()
799 {
800     eventFd_ = epoll_create(MAX_EPOLL_EVENT);
801     if (eventFd_ < 0) {
802         return false;
803     }
804     return true;
805 }
806 
WaitForRequest()807 void FaultLoggerDaemon::WaitForRequest()
808 {
809     AddEvent(eventFd_, defaultSocketFd_, EPOLLIN);
810     AddEvent(eventFd_, crashSocketFd_, EPOLLIN);
811     AddEvent(eventFd_, sdkdumpSocketFd_, EPOLLIN);
812     epoll_event events[MAX_CONNECTION];
813     DFXLOG_DEBUG("%s :: %s: start epoll wait.", FAULTLOGGERD_TAG.c_str(), __func__);
814     do {
815         int epollNum = epoll_wait(eventFd_, events, MAX_CONNECTION, -1);
816         if (epollNum < 0) {
817             if (errno != EINTR) {
818                 DFXLOG_ERROR("%s :: %s: epoll wait error, errno(%d).", FAULTLOGGERD_TAG.c_str(), __func__, errno);
819             }
820             continue;
821         }
822         for (int i = 0; i < epollNum; i++) {
823             if (!(events[i].events & EPOLLIN)) {
824                 DFXLOG_WARN("%s :: %s: epoll event(%d) error.", FAULTLOGGERD_TAG.c_str(), __func__, events[i].events);
825                 continue;
826             }
827 
828             int fd = events[i].data.fd;
829             if (fd == defaultSocketFd_ || fd == crashSocketFd_ || fd == sdkdumpSocketFd_) {
830                 HandleAccept(eventFd_, fd);
831             } else {
832                 HandleRequest(eventFd_, fd);
833             }
834         }
835     } while (true);
836 }
837 
CleanupEventFd()838 void FaultLoggerDaemon::CleanupEventFd()
839 {
840     DelEvent(eventFd_, defaultSocketFd_, EPOLLIN);
841     DelEvent(eventFd_, crashSocketFd_, EPOLLIN);
842     DelEvent(eventFd_, sdkdumpSocketFd_, EPOLLIN);
843 
844     if (eventFd_ > 0) {
845         close(eventFd_);
846         eventFd_ = -1;
847     }
848 }
849 
GetElfName(FaultLoggerdStatsRequest * request)850 std::string GetElfName(FaultLoggerdStatsRequest* request)
851 {
852     if (request == nullptr || strlen(request->callerElf) > NAME_BUF_LEN) {
853         return "";
854     }
855 
856     std::stringstream stream;
857     stream << std::string(request->callerElf, strlen(request->callerElf));
858     stream << "(";
859     stream << std::hex << request->offset;
860     stream << ")";
861     return stream.str();
862 }
863 
HandleDumpStats(int32_t connectionFd,FaultLoggerdStatsRequest * request)864 void FaultLoggerDaemon::HandleDumpStats(int32_t connectionFd, FaultLoggerdStatsRequest* request)
865 {
866     DFXLOG_INFO("%s :: %s: HandleDumpStats", FAULTLOGGERD_TAG.c_str(), __func__);
867     size_t index = 0;
868     bool hasRecord = false;
869     for (index = 0; index < stats_.size(); index++) {
870         if (stats_[index].pid == request->pid) {
871             hasRecord = true;
872             break;
873         }
874     }
875 
876     DumpStats stats;
877     if (request->type == PROCESS_DUMP && !hasRecord) {
878         stats.pid = request->pid;
879         stats.signalTime = request->signalTime;
880         stats.processdumpStartTime = request->processdumpStartTime;
881         stats.processdumpFinishTime = request->processdumpFinishTime;
882         stats.targetProcessName = request->targetProcess;
883         stats_.emplace_back(stats);
884     } else if (request->type == DUMP_CATCHER && hasRecord) {
885         stats_[index].requestTime = request->requestTime;
886         stats_[index].dumpCatcherFinishTime = request->dumpCatcherFinishTime;
887         stats_[index].callerElfName = GetElfName(request);
888         stats_[index].callerProcessName = request->callerProcess;
889         stats_[index].result = request->result;
890         stats_[index].summary = request->summary;
891         ReportDumpStats(stats_[index]);
892         stats_.erase(stats_.begin() + index);
893     } else if (request->type == DUMP_CATCHER) {
894         stats.pid = request->pid;
895         stats.requestTime = request->requestTime;
896         stats.dumpCatcherFinishTime = request->dumpCatcherFinishTime;
897         stats.callerElfName = GetElfName(request);
898         stats.result = request->result;
899         stats.callerProcessName = request->callerProcess;
900         stats.summary = request->summary;
901         ReportDumpStats(stats);
902     }
903     RemoveTimeoutDumpStats();
904 }
905 
RemoveTimeoutDumpStats()906 void FaultLoggerDaemon::RemoveTimeoutDumpStats()
907 {
908     const uint64_t timeout = 10000;
909     uint64_t now = GetTimeMilliSeconds();
910     for (auto it = stats_.begin(); it != stats_.end();) {
911         if (((now > it->signalTime) && (now - it->signalTime > timeout)) ||
912             (now <= it->signalTime)) {
913             it = stats_.erase(it);
914         } else {
915             ++it;
916         }
917     }
918 }
919 
ReportDumpStats(const DumpStats & stat)920 void FaultLoggerDaemon::ReportDumpStats(const DumpStats& stat)
921 {
922 #ifndef HISYSEVENT_DISABLE
923     HiSysEventWrite(
924         HiSysEvent::Domain::HIVIEWDFX,
925         "DUMP_CATCHER_STATS",
926         HiSysEvent::EventType::STATISTIC,
927         "CALLER_PROCESS_NAME", stat.callerProcessName,
928         "CALLER_FUNC_NAME", stat.callerElfName,
929         "TARGET_PROCESS_NAME", stat.targetProcessName,
930         "RESULT", stat.result,
931         "SUMMARY", stat.summary, // we need to parse summary when interface return false
932         "PID", stat.pid,
933         "REQUEST_TIME", stat.requestTime,
934         "OVERALL_TIME", stat.dumpCatcherFinishTime - stat.requestTime,
935         "SIGNAL_TIME", stat.signalTime - stat.requestTime,
936         "DUMPER_START_TIME", stat.processdumpStartTime - stat.signalTime,
937         "UNWIND_TIME", stat.processdumpFinishTime - stat.processdumpStartTime);
938 #endif
939 }
940 } // namespace HiviewDFX
941 } // namespace OHOS
942